1 puntos por GN⁺ 2 시간 전 | 1 comentarios | Compartir por WhatsApp
  • Entre las 19:20 y 19:26 UTC del 2026-05-11, un atacante publicó 84 versiones maliciosas en 42 paquetes npm de @tanstack/
  • La cadena de ataque combinó pull_request_target “Pwn Request”, contaminación de caché de GitHub Actions y extracción de tokens OIDC desde la memoria del runner
  • El token de npm y el workflow de publicación no fueron robados ni comprometidos; el malware hizo POST directo al registro con permisos de OIDC trusted publisher
  • Si se instalaron versiones afectadas, pudieron quedar expuestas credenciales de AWS, GCP, Kubernetes, Vault, GitHub, npm y SSH, por lo que deben rotarse
  • Todas las versiones afectadas fueron marcadas como deprecated, se avanzó con npm security y la eliminación de tarballs, y se publicaron el issue de seguimiento y el GitHub Security Advisory

Resumen del incidente

  • Entre las 19:20 y 19:26 UTC del 2026-05-11, un atacante publicó 84 versiones maliciosas en 42 paquetes npm @tanstack/*
  • La cadena de ataque combinó el patrón pull_request_target “Pwn Request”, contaminación de caché de GitHub Actions que cruza el límite de confianza entre fork y base, y extracción de tokens OIDC desde la memoria del proceso del runner de GitHub Actions
  • Se confirmó que los tokens de npm no fueron robados y que el workflow de publicación de npm en sí no fue comprometido
  • Las versiones maliciosas fueron detectadas públicamente en menos de 20 minutos por el investigador externo ashishkurmi de stepsecurity
  • Todas las versiones afectadas fueron marcadas como deprecated y, junto con npm security, se avanzó con la eliminación de los tarballs del registro
  • Los usuarios que instalaron versiones afectadas el 2026-05-11 deben rotar las credenciales de AWS, GCP, Kubernetes, Vault, GitHub, npm y SSH accesibles desde el host de instalación
  • El issue de seguimiento es TanStack/router#7383 y el GitHub Security Advisory es GHSA-g7cv-rxg3-hmpx

Alcance del impacto

  • Paquetes afectados

    • El alcance incluye 42 paquetes y 84 versiones; se publicaron 2 versiones por paquete con un intervalo aproximado de 6 minutos
    • La lista completa está incluida en el issue de seguimiento
    • Las familias de productos confirmadas como no afectadas son @tanstack/query*, @tanstack/table*, @tanstack/form*, @tanstack/virtual*, @tanstack/store y el metapaquete @tanstack/start
    • @tanstack/start-* no está incluido en la lista confirmada de no afectados
  • Comportamiento del malware

    • Cuando un entorno de desarrollo o CI ejecuta npm install, pnpm install o yarn install sobre una versión afectada, npm resuelve la entrada maliciosa de optionalDependencies y obtiene el commit huérfano del payload desde la red del fork
    • Después se ejecuta el script del ciclo de vida prepare, y entra en acción el router_init.js ofuscado de aproximadamente 2.3 MB oculto dentro del tarball afectado
    • El script malicioso recopila credenciales desde ubicaciones comunes, incluidas AWS IMDS/Secrets Manager, metadata de GCP, token de service account de Kubernetes, token de Vault, ~/.npmrc, token de GitHub, CLI gh, .git-credentials y claves privadas SSH
    • Los datos robados se exfiltran a través de la red de carga de archivos del mensajero Session/Oxen y los destinos son filev2.getsession.org y seed{1,2,3}.getsession.org
    • Como esa red está cifrada de extremo a extremo y no hay un C2 controlado por el atacante, la única mitigación a nivel de red es bloquear IP/dominios
    • La lógica de autopropagación enumera otros paquetes mantenidos por la víctima mediante registry.npmjs.org/-/v1/search?text=maintainer:<user> y luego los vuelve a publicar con el mismo método de inyección
    • Dado que el payload se ejecuta como parte del ciclo de vida de instalación de npm, los hosts que instalaron versiones afectadas el 2026-05-11 deben tratarse como potencialmente comprometidos

Cronología

  • Antes del ataque: fase de envenenamiento de caché

    • El 2026-05-10 a las 17:16 UTC, el atacante creó github.com/zblgg/configuration, un fork de TanStack/router, y le cambió el nombre para evitar que apareciera en búsquedas de la lista de forks
    • El 2026-05-10 a las 23:29 UTC, se creó en el fork el commit malicioso 65bf499d16a5e8d25ba95d69ec9790a6dd4a1f14 con la identidad manipulada claude <claude@users.noreply.github.com>
    • Ese commit agregó packages/history/vite_setup.mjs, un payload JS empaquetado de unas 30,000 líneas, y añadió [skip ci] al mensaje del commit para suprimir el CI del evento push
    • Alrededor de las 10:49 UTC del 2026-05-11, zblgg abrió el PR #7378 contra main de TanStack/router con el título “WIP: simplify history build”
    • Tanto bundle-size.yml como labeler.yml se ejecutaron automáticamente para el PR mediante pull_request_target, y como pull_request_target evita la barrera de aprobación para primeros contribuidores, no se necesitó aprobación adicional
    • pr.yml, que usa pull_request, quedó bloqueado en espera de aprobación y no se ejecutó
    • Entre las 11:01 y las 11:11 UTC del 2026-05-11, zblgg hizo varios force-push al head del PR, provocando ejecuciones adicionales de pull_request_target
    • El 2026-05-11 a las 11:11 UTC, el commit malicioso 65bf499d llegó al head del PR, y el job benchmark-pr de bundle-size.yml hizo checkout de refs/pull/7378/merge y luego ejecutó pnpm install y pnpm nx run @benchmarks/bundle-size:build, momento en que se ejecutó vite_setup.mjs
    • El 2026-05-11 a las 11:29 UTC, se guardó en TanStack/router una caché de GitHub Actions de 1.1 GB llamada Linux-pnpm-store-6f9233a50def742c09fde54f56553d6b449a535adf87d4083690539f49ae4da11
    • Esta caché se guardó con alcance refs/heads/main y se configuró para coincidir con la clave que release.yml consultaría en el siguiente push a main
    • El 2026-05-11 a las 11:31 UTC, el atacante revirtió el PR al HEAD de main de ese momento, b1c061af, para que el PR visible pareciera un no-op de 0 archivos, y en ese mismo minuto cerró el PR y borró la rama, pero la caché contaminada permaneció
  • Activación: fase de publicación

    • El 2026-05-11 a las 19:15 UTC, Manuel hizo merge del PR #7369, lo que provocó un push a main, y la ejecución del workflow release.yml 25613093674 comenzó a las 19:15:44 y luego falló
    • El 2026-05-11 a las 19:20:39 UTC, el registro de npm recibió la publicación de @tanstack/history@1.161.9 y de 41 paquetes hermanos
    • En total se publicaron unas 84 versiones distribuidas en 42 paquetes, pero en ese segundo exacto solo se ven aproximadamente la mitad; el resto se publicó en la segunda ejecución
    • La autenticación de publicación se hizo mediante un OIDC trusted-publisher binding para TanStack/router release.yml@refs/heads/main, pero no ocurrió desde el paso Publish Packages del workflow, que se omitió por fallas en las pruebas
    • Quien realmente publicó fue el malware ejecutado durante las etapas de prueba/limpieza, que acuñó un token OIDC con permiso id-token: write y luego hizo POST directamente a registry.npmjs.org
    • El 2026-05-11 a las 19:20:47 UTC, la ejecución 25613093674 terminó con estado failure
    • El 2026-05-11 a las 19:16 UTC, Manuel hizo merge del PR #7382, provocando un segundo push a main, y la ejecución del workflow 25691781302 comenzó a las 19:16:22
    • La segunda ejecución también restauró la misma caché contaminada, y el 2026-05-11 a las 19:26:14 UTC se publicó un segundo conjunto de versiones por paquete, como @tanstack/history@1.161.12, mediante el mismo mecanismo OIDC
    • El 2026-05-11 a las 19:26:20 UTC, la ejecución 25691781302 también terminó con estado failure
  • Detección y respuesta

    • Alrededor de las 19:50 UTC del 2026-05-11, el investigador externo carlini abrió el issue #7383 con la huella maliciosa de optionalDependencies y la lista de paquetes
    • La lista inicial incluía 14 de los 42, y el investigador también notificó directamente a npm security
    • Alrededor de las 20:00 UTC del 2026-05-11, Manuel confirmó el incidente en #7383 y comenzó la respuesta
    • Alrededor de las 20:10 UTC del 2026-05-11, Manuel eliminó los permisos de push de GitHub de otros miembros del equipo ante la posibilidad de compromiso de máquinas de usuarios
    • Alrededor de las 20:30 UTC del 2026-05-11, Tanner envió a security@npmjs.com la lista completa de IOC y una solicitud para retirar los tarballs del lado del registro, y presentó un reporte formal de malware a través de npm
    • Alrededor de las 21:00 UTC del 2026-05-11, un escaneo completo de los 295 paquetes @tanstack/* confirmó el alcance: 42 paquetes y 84 versiones
    • Tanner empezó la deprecación en npm de los 84 paquetes afectados, y @tan_stack y los maintainers publicaron avisos en Twitter/X, LinkedIn y Bluesky
    • El 2026-05-11 a las 21:30 UTC, se identificaron el vector de envenenamiento de caché con pull_request_target en bundle-size.yml y el fork zblgg/configuration
    • Se eliminaron mediante API las entradas de caché de todos los repositorios GitHub de TanStack/*
    • Se hizo merge de un PR de hardening para reconfigurar bundle-size.yml, se añadió una protección repository_owner y las referencias de actions de terceros quedaron fijadas por SHA
    • Se publicó el GitHub Security Advisory oficial y se solicitó un CVE

Causa raíz

  • Combinación de tres vulnerabilidades

    • El ataque necesitó las tres vulnerabilidades; ninguna por sí sola era suficiente
    • Cada vulnerabilidad conectó el límite de confianza de la otra: el código del PR del fork pasaba al caché del repositorio base, el caché del repositorio base pasaba al runtime del workflow de release, y el runtime del workflow de release llevaba a permisos de escritura en el registro de npm
  • Patrón “Pwn Request” de pull_request_target

    • bundle-size.yml se ejecutaba con pull_request_target para PR de forks, y dentro de ese contexto de trigger hacía checkout de la referencia merge del PR del fork y luego ejecutaba el build
    • La estructura clave era la siguiente
    on:
      pull_request_target:
        paths: ['packages/**', 'benchmarks/**']
    
    jobs:
      benchmark-pr:
        steps:
          - uses: actions/checkout@v6.0.2
            with:
              ref: refs/pull/${{ github.event.pull_request.number }}/merge # fork's merged code
    
          - uses: TanStack/config/.github/setup@main # transitively calls actions/cache@v5
    
          - run: pnpm nx run @benchmarks/bundle-size:build # executes fork-controlled code
    
    • El autor del workflow intentó separar el job comment-pr del job benchmark-pr para dividir los límites de confianza, y un comentario en el YAML indicaba la intención de mantener benchmark-pr como “untrusted with read-only permissions”
    • Sin embargo, el guardado post-job de actions/cache@v5 no se bloquea con permissions:, y la escritura del caché no usa el GITHUB_TOKEN del workflow sino un token interno del runner
    • Por lo tanto, la configuración permissions: contents: read no impidió la mutación del caché
    • El alcance del caché es a nivel de repositorio, y lo comparten la ejecución de pull_request_target que usa el alcance de caché del repositorio base y los pushes a main
    • Un PR que se ejecuta dentro del alcance de caché del repositorio base puede contaminar una entrada de caché que luego restaurará el workflow de producción de main
  • Envenenamiento del caché de GitHub Actions

    • El vite_setup.mjs malicioso fue diseñado para escribir datos de forma que coincidieran con la key del pnpm-store que el workflow legítimo release.yml calcularía y consultaría
    • La key objetivo tiene el formato Linux-pnpm-store-${hashFiles('**/pnpm-lock.yaml')}
    • Al terminar el job benchmark-pr, el post-step de actions/cache@v5 guardó el pnpm store contaminado exactamente con esa key
    • Después, cuando release.yml se ejecutó con un push a main, el step Setup Tools restauró la entrada contaminada exactamente como fue diseñado
    • Este tipo de ataque pertenece a la familia de envenenamiento de caché de GitHub Actions documentada por Adnan Khan en 2024, y no es un bug limitado a TanStack sino un problema de diseño de GitHub Actions que requiere mitigación consciente
  • Extracción del token OIDC desde la memoria del runner

    • release.yml declaraba legítimamente id-token: write porque lo necesitaba para npm OIDC trusted publishing
    • Cuando el pnpm store contaminado se restauraba en el runner, un binario controlado por el atacante quedaba presente en disco y era invocado durante el step de build
    • Ese binario encontraba el proceso Runner.Worker de GitHub Actions mediante /proc/*/cmdline y leía /proc/<pid>/maps y /proc/<pid>/mem para volcar la memoria del worker
    • Luego extraía de la memoria el token OIDC que el runner había emitido de forma lazy bajo la configuración id-token: write
    • Con el token extraído, autenticó directamente una solicitud POST a registry.npmjs.org, omitiendo por completo el step Publish Packages del workflow
    • Este método de extracción desde memoria es el mismo que se usó en el compromiso de tj-actions/changed-files en marzo de 2025, y se usó el mismo script en Python con comentario de atribución incluido
    • El atacante no inventó una técnica nueva, sino que recombinó investigación pública
  • Por qué cada elemento por sí solo no era suficiente

    • pull_request_target por sí mismo puede usarse para tareas confiables como labels o comentarios
    • El envenenamiento de caché por sí solo dentro de una dependency ya comprometida todavía requiere un vehículo aparte para publicar
    • La extracción del token OIDC por sí sola requiere ejecución previa de código en el runner

Detección e IOC

  • Ruta de detección

    • La detección no ocurrió internamente sino desde afuera
    • carlini abrió el issue #7383 unos 20 minutos después de la publicación y aportó un análisis técnico completo
    • Tanner recibió una llamada de Socket.dev confirmando la situación justo después de iniciar el war room
  • Fingerprints para maintainers downstream y herramientas de seguridad

    • En el manifiesto de los paquetes @tanstack/*, la siguiente entrada de optionalDependencies es el IOC clave
    "optionalDependencies": {
      "@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c"
    }
    
    • El IOC de archivo es router_init.js en la raíz del package; pesa unos 2.3 MB y no está incluido en "files"
    • La key del caché es Linux-pnpm-store-6f9233a50def742c09fde54f56553d6b449a535adf87d4083690539f49ae4da11
    • Las URL del payload de segunda etapa son https://litter.catbox.moe/h8nc9u.js, https://litter.catbox.moe/7rrc6l.mjs
    • La red de exfiltración es filev2.getsession.org, seed{1,2,3}.getsession.org
    • La identidad de commit falsificada es claude <claude@users.noreply.github.com>; no es el Claude real de Anthropic sino un email no-reply de GitHub manipulado
    • Las cuentas reales del atacante son zblgg id 127806521, voicproducoes id 269549300
    • El fork del atacante es github.com/zblgg/configuration, un fork de TanStack/router renombrado para evadir búsquedas
    • El commit huérfano del payload dentro de la red de forks es 79ac49eedf774dd4b0cfa308722bc463cfe5885c
    • Las ejecuciones del workflow que realizaron la publicación maliciosa son github.com/TanStack/router/actions/runs/25613093674 intento 4 y github.com/TanStack/router/actions/runs/25691781302

Lecciones

  • Qué salió bien

    • Investigadores externos detectaron el incidente y lo reportaron con todos los detalles técnicos en unos 20 minutos después del hecho
    • El equipo de maintainers se coordinó de inmediato a través de varias zonas horarias
    • La comunidad de detección obtuvo patrones de IOC públicos y claros en cuestión de horas
  • Qué necesitaba mejorar

    • No había alerting interno, y se enteraron del compromise por parte de un tercero
    • Se necesita monitoreo propio de publicación, y planean colaborar más estrechamente con empresas de investigación de seguridad del ecosistema que puedan detectar este tipo de problemas rápidamente y acortar el feedback loop
    • El workflow pull_request_target era conocido desde hace mucho como un patrón riesgoso, pero no había sido auditado
    • Las referencias flotantes de acciones de terceros como @v6.0.2 y @main crean un supply-chain risk permanente aparte de este incidente
    • Debido a la política de npm de “no se puede hacer unpublish si hay dependents”, no fue posible hacer unpublish de casi todos los paquetes afectados
    • Hubo que depender de npm security para la eliminación del tarball del lado del registry, lo que añadió varias horas durante las cuales los tarballs maliciosos siguieron pudiendo instalarse
    • La lista de 7 maintainers del scope de npm implica 7 objetivos separados de robo de credenciales para el mismo blast radius
    • El binding de trusted publisher de OIDC no tiene review por publicación; una vez configurado, cualquier code path dentro del workflow puede emitir un token con capacidad de publicación
    • La alternativa necesaria es pasar a tokens classic de corta duración con review manual, o agregar provenance-source-verification para detectar publicaciones desde pasos inesperados del workflow
  • Qué salió por suerte

    • El atacante eligió un payload que rompía las pruebas, por lo que el paso normal de publicación se omitió y no se generó un tarball que pareciera más limpio
    • Por eso, el ataque se hizo lo suficientemente ruidoso como para detectarse rápido
    • Si el atacante hubiera sido más cuidadoso y no hubiera roto las pruebas, podría haber publicado en silencio durante algunas horas más
    • El atacante reutilizó un script público de volcado de memoria que incluía un comentario de atribución y, al no escribir código nuevo, la coincidencia de IOC fue más rápida

Preguntas pendientes

  • Hay que confirmar si el step Setup Tools de bundle-size.yml realmente invocó actions/cache@v5
  • Hay que validar esto leyendo un post-job log de una de las ejecuciones pull_request_target para el PR #7378; un run id de ejemplo es 25666610798
  • Hay que verificar qué había en el primer commit head del PR antes de que desapareciera por un force-push; podría seguir en el reflog de GitHub
  • Hay que confirmar si la forma en que el commit malicioso entró al git object store del fork fue un git push directo o una creación desde la web UI de GitHub que habría dejado una entrada en el audit log
  • Hay que contrastar el historial de actividad de voicproducoes para confirmar si es una cuenta real o un sock puppet
  • Hay que verificar si el caché de npm, que parece mostrar 6 entradas duplicadas linux-npm-store-*, también fue contaminado y si realmente se usó
  • Hay que confirmar si el ataque necesitó Nx Cloud o si habría funcionado solo con el caché de GitHub Actions
  • Hay que identificar si dentro de la red de forks de TanStack/router existen otros forks con el commit huérfano del payload
  • Si otros forks alojan ese commit, la accesibilidad de github:tanstack/router#79ac49ee... se mantendría y la limpieza sería más difícil
  • Se necesita una auditoría para ver si otros repos de TanStack como router, query, table, form y virtual usan el mismo patrón estilo bundle-size.yml
  • Hay que obtener de npm support el número de usuarios que realmente descargaron las versiones afectadas durante la ventana de publicación
  • Hay que confirmar si las máquinas de los 7 maintainers fueron comprometidas por separado
  • Aunque en la publicación maliciosa no se usó un token npm de maintainer, la máquina del maintainer podría ser un objetivo secundario de la lógica de self-propagation

Referencias

1 comentarios

 
GN⁺ 2 시간 전
Comentarios de Hacker News
  • Hay que tener cuidado al revocar tokens. Parece que el payload instala un dead-man's switch en ~/.local/bin/gh-token-monitor.sh y lo registra como servicio de usuario de systemd en Linux y como LaunchAgent com.user.gh-token-monitor en macOS
    Hace polling a api.github.com/user cada 60 segundos con el token robado y, si el token se revoca y devuelve un HTTP 40x, ejecuta rm -rf ~/
    https://github.com/TanStack/router/issues/7383#issuecomment-...

    • En la práctica, si instalaste malware, de todos modos tienes que reiniciar por completo la computadora
    • Increíble. Es como una situación de destrucción mutua asegurada
      Los próximos 5 años en el mundo del software se van a poner realmente difíciles, y los sistemas con air gap probablemente van a volverse muy importantes
    • En realidad siempre debiste tener respaldos configurados, pero si este incidente hace que la gente los implemente, al menos algo bueno saldrá de esto
  • El paquete npm @mistralai/mistralai también fue comprometido como parte de este gusano
    https://github.com/mistralai/client-ts/issues/217
    Ahora ya fue retirado del registro de npm

  • Es desafortunado, pero esto parece demostrar que Trusted Publishing por sí solo no basta para publicar de forma segura desde CI. Si un atacante está dentro del pipeline de CI o roba privilegios de administrador del repositorio, puede publicar fácilmente
    No es información nueva, y tampoco es que Trusted Publishing haya sido diseñado para garantizar eso, pero al pasar de publicación local con autenticación de dos factores a Trusted Publishing, aparece esta vía de ataque mediante compromiso del CI. Básicamente desaparece el segundo factor que impedía ejecutar npm publish desde local
    Por cómo se desarrolló todo, parece que el atacante tomó control del pipeline de CI/CD y, como npm publish no tenía segundo factor, robó el token OIDC y completó la publicación. Como detalle interesante pero aparte, la tarea de despliegue en sí falló, pero el payload dentro del commit malicioso aparentemente pudo publicarse por su cuenta usando el token OIDC del workflow
    Lo deseable sería mantener el modelo de Trusted Publisher sin tokens de larga duración, pero con despliegues desde CI que conserven un segundo factor fuera de GitHub. Es decir, hace falta un despliegue por etapas donde alguien en npm tenga que promover el artefacto al estado realmente público mediante autenticación de dos factores
    Si la publicación solo puede ocurrir dentro del modelo de confianza de GitHub, cualquiera que robe un token de administrador del repositorio o inserte código malicioso en el pipeline puede completar la publicación con facilidad. Si existe un segundo factor real fuera del contexto de GitHub, aún podrían dañar el repositorio o plantar código malicioso, pero no publicarían sin ese segundo factor del registro

    • Tengo un paquete medianamente popular y sigo usando publicación local y autenticación de dos factores. Trusted Publishing se ve demasiado complejo y parece que lo hackean a cada rato, así que me pregunto si no será demasiado complejo para operarlo de forma segura y si no habría que rediseñarlo desde cero
    • Sigo pensando que Trusted Publishing es una gran mejora, pero la idea de exigir un segundo factor al marcar una release como realmente pública es buena. Eso haría muy difícil ejecutar este tipo de gusano en CI
    • Quiero hacer firmas con toque con algo como una YubiKey. La idea misma de confiar en que la nube gestione las credenciales por ti parece un error
    • En el blog de astral mostraron recientemente cómo usar Trusted Publishing y aun así poner una compuerta para la release, es decir, agregar una aprobación manual al workflow de publicación. Lamentablemente, la documentación de Trusted Publishing de NPM/PyPI/Rubygems ni siquiera menciona esta posibilidad, y tampoco la ofrece como opción por defecto
    • Nunca entendí del todo por qué la gente dice que Trusted Publishing marca alguna diferencia frente a este tipo de ataques a la cadena de suministro
  • Postmortem: https://tanstack.com/blog/npm-supply-chain-compromise-postmo...

    • Se agradece el postmortem de TanStack, pero desde la perspectiva del ecosistema npm en general, me parece que el tema de seguridad sigue siendo una preocupación en curso
      Me pregunto si hay alguna evidencia de que se pueda considerar seguros a los paquetes descendientes que pudieran haber importado o incluido paquetes de TanStack
  • Los scripts de postinstall son letales. Todos deberían usar pnpm
    No tiene sentido que un commit “huérfano” enviado a un FORK pueda provocar algo así desde el cliente npm. Creo que GitHub también tiene una gran responsabilidad. Es completamente absurdo que commits de un fork malicioso puedan accederse mediante URIs indistinguibles de las de un repositorio legítimo a través del almacenamiento compartido de objetos de GitHub

    • Si ejecutas la app con la dependencia actualizada, ese código igual se ejecuta. No importa si es root o no root; lo importante es que las cosas valiosas son accesibles con los privilegios del usuario que ejecuta la aplicación
    • No entiendo cómo esto no es una incidencia P0 para GitHub. ¿Alguien puede explicarlo?
      Cuando lo leí por primera vez, pensé que habían usado mal la palabra “fork” y que en realidad querían decir una rama del repositorio oficial. Me parecía imposible que fuera real, pero madre mía
  • https://tanstack.com/blog/npm-supply-chain-compromise-postmo...
    TanStack acaba de publicar el postmortem de este incidente

  • Este es un recordatorio para configurar tu entorno npm de forma segura
    https://gajus.com/blog/3-pnpm-settings-to-protect-yourself-f...
    Con solo unas cuantas configuraciones puedes reducir mucho el problema

    • En npm v11 o superior también existe allow-git=none: https://github.blog/changelog/2026-02-18-npm-bulk-trusted-pu...
    • Creo que este artículo está equivocado sobre la edad mínima de release en npm. 1) El nombre de la configuración es min-release-age. 2) Por alguna razón lo hicieron en días y no en minutos: https://docs.npmjs.com/cli/v11/using-npm/config#min-release-...
      Me parece que el espacio de los gestores de dependencias está fragmentado de una forma completamente innecesaria
    • Es exagerado afirmar que si configuras una edad mínima de 7 días “jamás” sufrirás una vulnerabilidad de cadena de suministro en npm
    • Hay que fijar todas las dependencias sin falta
      Si la dependencia de versión del paquete está como ^1.0.0 o incluso "*", deja de leer y fíjala de inmediato a una versión segura
  • Lo hice rápido con Claude para ayudar a frenar la propagación. Obviamente hay que verificarlo por cuenta propia, pero escanea si los paquetes comprometidos mencionados están en tu máquina: https://github.com/PaulSinghDev/tanstack-shai-hulud-fix

  • Parece que ya llegamos al punto en que todo el mundo debería ejecutar cada proyecto en una VM individual
    Vistas las vulnerabilidades recientes de elevación de privilegios local, Docker por sí solo para nada es suficiente. Además, los contenedores nunca fueron diseñados para ser el límite principal de seguridad

    • Devcontainers es la forma más conocida de este concepto de “entorno de desarrollo aislado”, pero no es una VM completa y tampoco te habría protegido por completo en este caso. Las credenciales de GitHub entran automáticamente al contenedor
      Si hay otros servicios en la nube a los que necesitas acceder desde dentro del contenedor, este ladrón de credenciales también se los llevaría. Aun así, sí reduce el radio de impacto, así que al menos es una mejora
    • QubesOS va en la dirección correcta. Dan ganas de tener múltiples VM en la raíz y capas superpuestas de seguridad
    • Si de verdad quieres usar contenedores, también puedes poner una VM por cada contenedor. Haber ejecutado todo en VM en lugar de en servicios arbitrarios de Kubernetes me ha dejado bastante tranquilo estas últimas semanas
    • Por suerte, los proyectos que usan ecosistemas de lenguajes más seguros, como C y C++, están libres de este problema :-)
  • Vaya, otro paquete enorme. Vuelvo a publicar el aviso de interés público que compartí después de que comprometieran Axios y LiteLLM. También aplica lo de los scripts de ciclo de vida
    npm/bun/pnpm/uv ahora ya soportan configurar una edad mínima de release para los paquetes. También tengo ignore-scripts=true en ~/.npmrc, y por lo visto ese ajuste por sí solo habría mitigado esta vulnerabilidad. bun y pnpm no ejecutan scripts de ciclo de vida por defecto
    Así es como se configura globalmente una edad mínima de release de 7 días
    ~/.config/uv/uv.toml
    exclude-newer = "7 days"
    ~/.npmrc
    min-release-age=7 # days
    ignore-scripts=true
    ~/Library/Preferences/pnpm/rc
    minimum-release-age=10080 # minutes
    ~/.bunfig.toml
    [install]
    minimumReleaseAge = 604800 # seconds
    Si necesitas sobrescribir la configuración global, puedes usar flags de CLI
    npm install --min-release-age 0
    pnpm add --minimum-release-age 0
    uv add --exclude-newer "0 days"
    bun add --minimum-release-age 0
    Agrego una cosa más: parece haber preocupación de que si se adopta masivamente un tiempo de espera para dependencias, eso retrase el descubrimiento de vulnerabilidades o convierta ese tiempo de espera en una especie de free ride, pero no estoy de acuerdo. Lo que se intercambia con el tiempo de espera para dependencias es la preferencia temporal, y siempre habrá personas con una preferencia temporal más alta que la mía
    0: https://news.ycombinator.com/item?id=47582220
    1: https://news.ycombinator.com/item?id=47513932

    • De acuerdo. Por suerte activé esas configuraciones en marzo, antes de las dos olas anteriores. Además, conviene hacer commit del lockfile al repositorio y tener cuidado al agregar dependencias nuevas
      Para evitar cambios inesperados, puedes usar pnpm install --frozen-lockfile. Si no configuraste min-release-age, recuerda que también puedes terminar arrastrando paquetes afectados a través de dependencias transitorias. Si es posible, también conviene fijar la versión del gestor de paquetes