3 puntos por GN⁺ 2025-09-20 | 1 comentarios | Compartir por WhatsApp
  • Se produjo un incidente en el que múltiples paquetes de npm que incluían el paquete de código abierto @ctrl/tinycolor quedaron infectados con versiones maliciosas; la causa fue el robo de un token de npm a través de un workflow de GitHub Actions en un repositorio compartido
  • El atacante usó un token de npm con permisos amplios para publicar código malicioso en aproximadamente 20 paquetes; entre ellos, @ctrl/tinycolor tenía un gran impacto por alcanzar 2 millones de descargas semanales
  • Las versiones infectadas ejecutaban una carga maliciosa en la etapa de postinstall, y los equipos de seguridad de GitHub y npm respondieron rápidamente con medidas de eliminación y limpieza
  • El autor preparó un plan de seguridad reforzado para evitar reincidencias, incluyendo la migración a Trusted Publishing (OIDC), minimización de permisos de tokens, obligatoriedad de 2FA y uso de funciones de pnpm
  • Este incidente muestra la fragilidad de la seguridad en la cadena de suministro de software y evidencia la necesidad de mejorar las funciones de seguridad y las prácticas de seguridad en todo el ecosistema de npm

TL;DR

  • Un workflow malicioso de GitHub Actions fue enviado a un repositorio compartido y robó un token de npm
  • Con ese token, el atacante publicó versiones maliciosas de 20 paquetes, y entre ellos @ctrl/tinycolor tuvo mayor alcance por su alto volumen de descargas
  • Ni la cuenta personal ni los repositorios fueron comprometidos directamente, y tampoco hubo phishing ni instalación local de malware
  • Gracias a la rápida respuesta de los equipos de seguridad de GitHub y npm, las versiones maliciosas fueron eliminadas y luego se volvieron a publicar versiones limpias para depurar la caché

Cómo me enteré (How I Found Out)

  • En la tarde del 15 de septiembre, el miembro de la comunidad Wes Todd avisó del problema por DM en Bluesky
  • Para entonces, los equipos de seguridad de GitHub y npm ya estaban organizando la lista de paquetes afectados e iniciando las medidas de eliminación
  • Como pista inicial, se compartió el nombre de una rama maliciosa, 'Shai-Hulud', tomado del nombre del gusano de arena del universo de Dune

Lo que realmente pasó (What Actually Happened)

  • En el repositorio de angulartics2, con el que se había colaborado hace mucho tiempo, todavía había un colaborador con permisos de administrador
  • El token de npm almacenado en ese repositorio fue robado por un workflow malicioso de GitHub Actions
  • Con ese token, el atacante publicó cerca de 20 paquetes, incluido @ctrl/tinycolor
  • Los equipos de seguridad de GitHub y npm eliminaron rápidamente las versiones maliciosas, y el autor volvió a publicar nuevas versiones confiables

Impacto (Impact)

  • Al instalar una versión maliciosa, se ejecutaba un script de postinstall, generando un riesgo de seguridad
  • Se recomienda a los usuarios afectados consultar la guía de respuesta inmediata de StepSecurity

Entorno de publicación y plan de respuesta (Publishing Setup & Interim Plan)

  • Antes se realizaba la publicación automática con la combinación semantic-release + GitHub Actions
  • Aunque se usaba la función de provenance de npm, esta no podía detener a un atacante con un token válido
  • En adelante, se planea eliminar los tokens estáticos mediante la adopción de Trusted Publishing (OIDC)
  • Por ahora, se revocaron todos los tokens y se están aplicando medidas adicionales de seguridad como 2FA obligatoria, permitir solo tokens con permisos granulares y evaluar la función minimumReleaseAge de pnpm

Mejoras ideales (Publishing Wishlist)

  • Hace falta una opción a nivel de cuenta de npm para forzar Trusted Publishing basado en OIDC
  • Se necesita una función para bloquear publicaciones cuando falte provenance, así como soporte completo para la integración entre semantic-release y OIDC
  • Se desea que la interfaz de GitHub ofrezca una función de publicación con aprobación manual basada en 2FA
  • Debería ser posible usar protecciones al nivel de GitHub Environments incluso sin una suscripción Pro
  • En la página de paquetes de npm, debería mostrarse si existe un script de postinstall y hacerse público el motivo de las versiones eliminadas

1 comentarios

 
GN⁺ 2025-09-20
Comentarios en Hacker News
  • En ese repositorio todavía quedaban secrets de GitHub Actions, es decir, un token de npm con permisos amplios de publicación
    Una de las ventajas de Trusted Publishing es que ya no hace falta usar tokens de publicación de larga duración
    Ahora solo se usan tokens generados temporalmente en la VM de CI y solo son válidos por 15 minutos
    Ya se está aplicando en varios ecosistemas como PyPI, npm, Cargo y Homebrew
    Incluso el proceso de publicación se vuelve un poco más fácil, así que recomiendo que todos lo usen
    Si la documentación todavía les parece poco clara, siempre pueden pedir ayuda
    Los administradores del ecosistema claramente quieren que esta función se adopte ampliamente
    Documentación oficial de Trusted Publishing

    • Apenas me enteré esta vez de que ahora npm permite Trusted Publishing
      Noticia relacionada
      Voy a configurarlo este fin de semana

    • Estaría bien que hubiera una bandera para indicar en el repositorio que un proyecto usa este tipo de función
      Así sería fácil bloquear paquetes de dependencias que no lo usen

  • Siento que no se ha prestado suficiente atención al tema de incluir MFA (autenticación multifactor) en el proceso de despliegue automático
    Publicar desde un workflow de CI y confirmar la publicación con un prompt de MFA no tendría problema, pero la última vez que lo revisé era complicado porque había que abrir un túnel HTTPS para entregar el código
    Ojalá npm o GitHub ofrecieran una forma directa de proporcionar y confirmar un código MFA fácilmente durante CI

    • La publicación de paquetes tiene dos etapas: subir el paquete a npmjs y hacerlo realmente visible para los usuarios
      Actualmente esas dos etapas están unidas en una sola operación
      Yo separaría eso: que el sistema de CI solo construya y suba automáticamente
      Y para publicar de verdad el paquete subido, una persona tendría que iniciar sesión manualmente en el sitio de npmjs y pasar por la publicación y el MFA

    • La verdad, me pregunto si el concepto mismo de publicar paquetes sigue siendo necesario
      Si el VCS es la “fuente real”, ¿por qué no usarlo directamente sin un proceso de publicación aparte?
      Go de hecho funciona así
      Importa paquetes directamente por URL y maneja el versionado con tags
      Así solo hay que confiar en el VCS, lo que reduce la superficie de ataque adicional
      No hace falta revisar diff de archivos archivados por separado, solo cambios a nivel de commits
      El problema es que si mueves el repositorio cambia la ruta de importación, aunque eso también podría verse como una ventaja
      Fuera de eso, no veo muy claro qué beneficio aporta una etapa separada de publicación
      Parece un vestigio de la época en que se subían archivos tar por FTP

  • Antes trabajé en un repositorio compartido llamado angulartics2
    Ahí todavía había un secret de GitHub Actions con un token de npm que tenía permisos amplios de publicación
    Además, uno de los colaboradores tenía permisos sobre varios proyectos, y supongo que por eso varios paquetes se vieron afectados al mismo tiempo
    Se hizo un force push de una nueva rama llamada Shai-Hulud junto con un workflow malicioso de GitHub Actions
    Como era un colaborador con permisos de administrador, el workflow se ejecutó de inmediato sin requerir revisión y el token de npm se filtró
    Con ese token filtrado se publicaron versiones maliciosas en 20 paquetes
    La mayoría eran paquetes poco usados, pero @ctrl/tinycolor es un paquete popular con unas 2 millones de descargas por semana
    Lo que todavía no entiendo es cómo con el token de npm del repositorio de angulartics2 también se pudo publicar tinycolor

    • Yo también tengo permisos de administrador en el repositorio de npm de otra persona y últimamente casi todos los releases los hago yo
      Desde que me volví administrador me dieron ganas de arreglar varios problemas pendientes de hace tiempo, así que también hay muchos commits con mi nombre
      Casi me había decidido a publicar paquetes con GitHub Actions, pero siempre me preocupó que al desplegar manualmente con 2FA pudiera terminar publicando por error algo que no fuera el estado correcto de master
      Por eso había postergado hablarlo con otros administradores, y viendo lo que pasó, siento que fue bueno haberlo aplazado
      No sé cuál sea la respuesta correcta, pero claramente dejar credenciales en manos de terceros no parece una buena solución

    • ¿Por qué el token de npm de angulartics2 tendría permisos para publicar tinycolor?
      Eso suena totalmente a una ruta clásica de hackeo organizacional
      Los “pecados del pasado” que dejaste ahí terminan alcanzándote tarde o temprano
      Hace unos años nos pasó algo así en nuestra organización
      Una falla de seguridad que quedó en un editor antiguo, que ya habíamos reemplazado tres veces, seguía permitiendo subidas al servidor
      Ni siquiera lo encontramos en build time, sino escaneando URLs

    • Perdón si no me expliqué bien
      Ese token tenía permisos globales de publicación sobre todos mis paquetes de npm

  • Llevo 10 años defendiendo los releases manuales
    Siempre me criticaron bastante, pero últimamente ya no parece una idea tan extraña
    Sé que CI/CD suena genial, pero viendo este incidente y el tema reciente de CF, hay cada vez más pruebas de que la automatización también facilita que ocurran problemas graves
    Cuando trabajaba en BigBank, para desplegar a producción al menos cinco personas tenían que estar pendientes y había muchos pasos, pero al menos sabíamos con certeza qué se estaba publicando

    • Totalmente de acuerdo
      No por culpa de GitHub Actions ni de scripts automáticos de release, sino porque creo que el método antiguo de compilar a mano, firmar, subir el tarball y verificarlo es mucho más seguro
      Los sistemas de distribución, como los de empaquetado tipo Debian, además tienen etapas separadas de verificación, y esa es parte de la razón por la que el incidente de xz no terminó hackeando todo internet
      Como mínimo, debería ser obligatorio que una persona firme manualmente los binarios antes de que se publiquen los releases
      Como también existe el problema de que un atacante se agregue como maintainer y firme con su propia clave, sería aún más seguro si se combinara con gestión de claves confiables al estilo de los sistemas de empaquetado de distribuciones
      Si tu modelo de amenazas parte de “si se filtra una sola cuenta de GitHub o una sola API key, todos los usuarios quedan comprometidos”, vale la pena preguntarse seriamente si eso es razonable
  • Usar 2FA para publicar está bien, pero sería mucho más seguro si varios autores tuvieran que aprobar mediante firmas criptográficas
    No debería bastar con comprometer a una sola persona para que el ataque tenga éxito

    • Muchos paquetes solo tienen un autor

    • Exigir firmas de varios autores también está bien, pero si hubiera verificación de firmas de commits, tags y artefactos de alguna forma, se podrían bloquear la mayoría de los ataques
      Los sistemas de empaquetado de distribuciones sí tienen muy buen soporte para verificación de firmas, pero los package managers de lenguajes carecen de ese tipo de mecanismos
      Por ejemplo, el proceso oficial de release de runc se firma por completo con claves de mantenedores, guardadas en Yubikeys y similares
      Los sistemas de distribuciones también administran keyrings separados para verificar las fuentes oficiales y los binarios
      Si hubiera existido un proceso así, creo que este ataque se habría frenado en varias etapas
      Se puede compilar directo en CI, pero al final hace falta una estructura en la que el maintainer firme manualmente
      Si los package managers de lenguajes no ofrecen este tipo de workflow, entonces Trusted Publishing es al menos una alternativa menos mala
      Pero si la cuenta de GitHub es comprometida, por ejemplo por robo de cookies, igual se puede publicar de inmediato
      GitHub ofrece configuraciones de seguridad como timeouts para Trusted Publishing, pero un atacante también podría desactivarlas
      Aunque comprometan mi cuenta, una distribución no aceptaría cambios firmados con una clave que yo no haya firmado, así que es relativamente más seguro
      Referencia: trabajo en SUSE, pero me gustaría que openSUSE, Arch y Gentoo, entre otras, ampliaran aún más el soporte de verificación de artefactos
      Enlaces relacionados:

    • runc.keyring

    • keyring_validate.sh

    • release_sign.sh

    • runc.keyring de openSUSE

  • Odio los tokens
    Un token no es más que una contraseña estática
    Creo que hace falta una forma de autenticación mejor hecha
    Por ejemplo, usar GitHub como proveedor de tokens para AWS me parece una de las opciones más razonables
    Integración Github-AWS con OIDC
    Pero este caso sigue siendo más bien una excepción

    • Los flujos OIDC entre máquinas pueden ser seguros si se implementan bien, pero la configuración es demasiado compleja
      Y al final OIDC también se siente como “un token más complejo”
      Si es un entorno automatizado sin verificación humana, siempre queda algo que puede filtrarse en algún punto, ya sea el token o el generador de tokens
      Incluso en este caso del gusano, OIDC no era una solución de fondo
      Si el workflow de GitHub fue comprometido, con OIDC o sin él igual se inyecta una identidad temporal en el entorno
      Lo importante al final es tener un sistema en el que un usuario no autorizado no pueda ejecutar workflows con acceso a secrets
      Si quieres dividir permisos de manera más fina, tal vez sea más efectivo reducir el alcance de los tokens que usar OIDC

    • La idea original de los tokens es que tengan una vida útil limitada y un alcance de permisos (authZ) restringido
      Pero en la mayoría de los casos no funcionan así y terminan usándose de forma estática, como si fueran contraseñas
      Existen alternativas como oauth o biscuits, que permiten limitar permisos de forma detallada, pero en la práctica casi no se usan

    • Trusted Publishing ahora ya está soportado por varios registros de paquetes, incluido npm
      Noticia relacionada

    • Como ya mencionó alguien más, los tokens deberían emitirse solo con vida corta o después de autenticación manual, como MFA o passphrase

    • Usar mTLS (certificados cliente TLS) va más en la dirección correcta

  • ¿Alguien conoce alguna herramienta o script público para revisar paquetes npm vulnerables?
    En la página de stepsecurity no parece haber algo así

    • No bloquea todo, pero implementar provenance-action también parece una buena idea
      provenance-action

    • Para problemas conocidos, lo básico es usar npm audit

  • La publicación basada en 2FA local no es sostenible
    ¿Por qué no sería sostenible la publicación local con 2FA?
    El verdadero problema es el workflow de publicación automatizada
    No creo que la mayoría de los paquetes npm se publiquen tan seguido ni necesiten un proceso de release tan complejo
    ¿Qué tiene de tan difícil que una persona haga npm publish manualmente con 2FA?
    Si hasta eso da flojera, entonces quizá hay que replantearse cuántos paquetes se están manteniendo

    • Tiene sentido
      Lo que quise decir es que me preocupaban más bien errores en la publicación local, como estar en la rama equivocada o dejar fuera algo del build
  • Me pregunto qué pasaría si un job de CI hiciera force push y modificara partes profundas del historial de git

  • El status quo ya no está funcionando bien
    Claro, se pueden elogiar ventajas técnicas como los tokens OIDC o las soluciones zero trust
    Pero una parte importante de los mantenedores de librerías npm con millones de descargas en realidad no va a prestar atención a la seguridad hasta que los hackeen o hasta que npm directamente les bloquee la publicación
    Y también aparecen propuestas imposibles de ejecutar, como “eliminemos todas las dependencias y dejemos solo la librería estándar”
    Reducir dependencias está bien, pero no resuelve en nada el problema que ya existe
    Siendo realistas, solo quedan dos caminos: que decenas o cientos de miles de personas abandonen npm y reescriban todo su código, o que npm imponga requisitos como 2FA u OIDC, al menos para paquetes con muchas descargas, y que bloquee por completo la publicación si no se cumplen
    Está bastante claro cuál de las dos opciones es más viable en la práctica
    De lo contrario, la reputación de npm se va a desplomar y terminaremos en una situación tipo XKCD 927