Mi relación tóxica con North Korea’s hijack of one of the web’s most used open source projects was likely weeks in the maki...

Cuando el npm install te instala un backdoor: la lección que el open source no quiere aprender Por: El Dev Senior Quemado (sí, ese que lleva 15 años apagando...

Mi relación tóxica con North Korea’s hijack of one of the web’s most used open source projects was likely weeks in the maki...

Cuando el npm install te instala un backdoor: la lección que el open source no quiere aprender

Por: El Dev Senior Quemado (sí, ese que lleva 15 años apagando fuegos que otros encienden con un --save-dev)

Vamos a hablar de lo que pasó con ese proyecto open source popular cuyas actualizaciones maliciosas salieron directamente desde la máquina de un top developer. Un ataque de actores norcoreanos. Una campaña de largo recorrido. Y una comunidad entera que, un día cualquiera, hizo npm update y se instaló un regalo con lazo.

Antes de que vengáis con las antorchas: no, esto no es un fallo de "los mantenedores son unos descuidados". Es un fallo sistémico de una industria que construye rascacielos sobre cimientos que nadie audita porque "es open source, seguro que alguien lo habrá mirado".

Spoiler: nadie lo miró. Nunca nadie lo mira. El open source es seguro porque es visible, dicen. Y el tráfico en la autopista también es visible y por eso mismo hay accidentes.


La cadena de suministro es el nuevo perímetro (y el perímetro está en llamas)

Durante años nos reímos de los que hacían left-pad y rompían medio internet. Qué graciosos. Resulta que la broma de verdad es que tu aplicación depende de 1.400 paquetes y no sabes qué hace ni el 3% de ellos.

Y ahora resulta que el eslabón débil no era el paquete X abandonado desde 2016. El eslabón débil era el portátil de la persona que tiene permisos de publicación.

Vamos a ser honestos sobre la ingeniería social y el compromiso de endpoints:

  • Los atacantes no rompieron criptografía. No hacía falta.
  • No encontraron un 0-day en el compilador. Comprometieron a una persona.
  • Y cuando tienes la máquina del mantenedor, tienes la signing key, tienes el token de npm, tienes todo. Es como robarle las llaves del edificio al conserje.

Llevamos años diciendo "confía en el código, no en la persona". Mentira. En el open source confías en la persona, en su máquina, en su red doméstica y en el café que se tomó el día que aprobó un PR sin leerlo.


La deuda técnica que nadie factura: seguridad de los mantenedores

Aquí viene la parte que me hace gruñir.

Cuando hablamos de deuda técnica siempre pensamos en código espagueti, en el monolito que nadie se atreve a tocar, en el TODO: refactor de 2014. Pero hay una deuda técnica que no aparece en el Jira: la deuda de infraestructura humana del open source.

  • Un npm package con 10 millones de descargas semanales mantenido por una persona en su tiempo libre.
  • Sin 2FA obligatorio hasta que es tarde.*
  • Sin hardware keys, sin máquinas dedicadas a publicar, sin separación entre "mi portátil donde miro el correo" y "la máquina que firma releases".
  • Sin presupuesto para que esa persona tenga, literalmente, un portátil limpio solo para builds.

Antes se hacía así: alguien subía el tarball a mano desde su ~/dev. Y funcionaba porque el ecosistema era pequeño y nadie te quería atacar. Ahora el ecosistema es infraestructura crítica global mantenida con la misma rigurosidad que el grupo de WhatsApp de la comunidad de vecinos.


Escenario hipotético (que ya es real, solo que no te has enterado)

Imagina esto, que es exactamente lo que pasó y lo que seguirá pasando:

  1. El atacante estudia al mantenedor durante meses. Redes sociales, patrones de commit, horarios.
  2. Compromete su estación de trabajo. Un phishing, un keylogger, una extensión de VS Code, un postinstall de un paquete que el propio dev instaló. Da igual el vector.
  3. Espera. No tiene prisa. Esto no es un ransomware de fin de semana; es una campaña de Estado.
  4. Publica una versión. La versión pasa los tests. Parece legítima. Porque fue publicada por la cuenta correcta.
  5. Tú, tres semanas después, haces npm ci en el CI y firmas el desastre.

Y aquí el detalle que me quema: todo el pipeline de seguridad moderno (SCA, SBOM, firmas) probablemente lo habría dejado pasar, porque la firma era válida. Auditamos el qué (el código) pero no el quién ni el cómo ni el desde dónde.


Lo que un senior quemado propone (y que probablemente ignoraréis)

No voy a vender humo de "la IA detectará el malware". La IA no sabe si tu postinstall es legítimo o exfiltración; para eso necesitas contexto, que es lo que la IA no tiene. Y no, el --ignore-scripts global no es una estrategia, es una tirita.* (Aunque, oye, empieza por ahí y me ahorras un susto).

Lo que sí haría, y que llevo años diciendo en reuniones donde me miran como si hablara en arameo:

  • Endurecer la publicación de releases: builds en entornos efímeros y aislados, nunca desde el portátil del mantenedor. Un dev, una máquina, un token es la receta del desastre.
  • Hardware keys obligatorias para publicar en los paquetes de la "liga A". Sin YubiKey, sin release.
  • Separación de roles: el que escribe el código no es necesariamente el que publica. Rotación, revisión y dos pares de ojos.
  • Pinning + lockfiles + hash de integridad, porque actualizar a ciegas "porque hay versión nueva" es como aceptar caramelos de un desconocido. Que sí, que el lockfile también puede comprometerse, pero al menos tienes un punto de control.
  • Financiar el mantenimiento crítico. Pagar a un mantenedor no es caridad, es seguro de continuidad de negocio. Tú, CTO, que gastas 200k en licencias de observabilidad, ¿cuánto das a los 3 paquetes que sostienen tu facturación?

El momento incómodo

Y ahora la parte que no querías leer, la que dejo aquí para que tú, humano, critiques y decidas:

El open source no es más seguro porque sea abierto. Es más seguro cuando alguien, de verdad, mira. Y "alguien" no es una multitud anónima de ojos que en teoría todo lo ven, sino una persona con tiempo, herramientas y ganas. Que, casualmente, es lo que nadie financia.

La crítica humana que dejo sobre la mesa: ¿de quién es la responsabilidad cuando el paquete "gratis" viene con backdoor? ¿Del voluntario que lo mantiene en su tiempo libre? ¿De la empresa que lo consume sin verificar? ¿Del registro que no impone 2FA a tiempo? ¿De la industria entera que confunde "popular" con "auditado"?*

Mientras lo decidís, yo sigo aquí, mirando mis package.json con desconfianza y añadiendo un --ignore-scripts a mi vida. Total, para lo que sirven las actualizaciones últimamente...