flawopen.com/Incidents/shai-hulud-npm-worm-september-2025
Shai-Hulud: el gusano de npm de septiembre de 2025 y la confianza al instalar
La campaña Shai-Hulud de septiembre de 2025 usó cuentas comprometidas de mantenedores de npm y ganchos postinstall maliciosos para robar credenciales y publicar más paquetes infectados.[1]
Imagina una fábrica que recibe una caja de piezas con instrucciones que se ejecutan solas al abrirla. Copian las acreditaciones de envío de la fábrica y las usan para mandar cajas manipuladas a otras. Desactivar esas instrucciones automáticas cierra una entrada, pero las piezas aún necesitan revisión antes de usarse.[1]
Conceptos Clave y Términos
Lifecycle hook- En septiembre, postinstall de npm ejecutaba código malicioso durante la instalación. Era comportamiento incluido en el paquete, no una vulnerabilidad de memoria de npm con CVE.
Publishing credential- Un token de npm otorga los permisos configurados para la cuenta o el paquete. La autoridad de publicación robada facilitó la propagación; duración, alcance y MFA dependen de la política.
Trusted publishing / OIDC- OIDC permite a un flujo de CI autorizado obtener credenciales de publicación breves sin guardar un token npm. Un flujo autorizado comprometido sigue siendo peligroso.
Mapeos de marcos
Cronología del Incidente
GitHub afirma que recibió el aviso sobre Shai-Hulud.[1]
GitHub comunicó que retiró más de 500 paquetes comprometidos y bloqueó cargas que coincidían con los indicadores del programa malicioso.[1]
Flujo de Ataque Paso a Paso
Código Fuente: Vulnerable vs. Seguro
Comparación segura de planes de instalación en Python: ninguna función ejecuta npm, lee credenciales ni consulta el registro. El ejemplo sigue la documentación de npm v10. El plan reforzado exige un archivo de dependencias revisado, suprime scripts de instalación y no hereda variables de entorno. Un ejecutor real debe proporcionar un binario npm conocido y un directorio personal y configuración aislados, sin secretos ni montajes sensibles. --ignore-scripts no vuelve seguras las importaciones posteriores ni los scripts invocados explícitamente; fijar versiones no certifica código benigno.
def install_plan(reviewed_lockfile, inherited_env):
# Solo devuelve un plan: no instala paquetes ni ejecuta comandos.
return {"argv": ["npm", "ci"],
"env": dict(inherited_env)}
def install_plan(reviewed_lockfile, inherited_env):
# Solo devuelve un plan: no instala paquetes ni ejecuta comandos.
if reviewed_lockfile is not True:
raise ValueError("Review the lockfile before installation")
return {"argv": ["npm", "ci", "--ignore-scripts"],
"env": {}}
Lista de Verificación de Seguridad para Ingeniería
- ✓Exija un archivo de dependencias revisado y npm ci --ignore-scripts en el trabajo de instalación; pruebas de política CI deben comprobar el comando y la ausencia de secretos en el entorno. Ejecute ganchos necesarios solo tras revisarlos en otro trabajo aislado.[3]
- ✓Excluya credenciales de publicación y nube del trabajo de dependencias, también de directorios personales, archivos montados e identidades del ejecutor. Pruebe que no pueda obtener credenciales de publicación.[1], [2]
- ✓Use publicación confiable si está disponible y limite flujo, rama y entorno autorizados; revise los cambios. Exija MFA resistente al phishing y retire tokens sin uso.[1]
- ✓Si hay exposición confirmada, aísle y reconstruya ejecutores, revoque credenciales expuestas y audite versiones y cambios de flujos. Revise el código de las dependencias: un archivo fijado o esperar antes de actualizar no certifican seguridad.[1], [2]