Caso de Estudio: Ataque Supply Chain axios
El 31 de marzo de 2026, una cuenta comprometida de maintainer de axios publicó versiones con backdoor (1.14.1 y 0.30.4) que inyectaban un RAT multiplataforma vía plain-crypto-js. Microsoft atribuyó el ataque a Sapphire Sleet, actor de estado norcoreano. La ventana de exposición fue de aproximadamente 3 horas.
El Vector de Ataque
npm install axios@1.14.1
└─ postinstall hook
└─ descarga plain-crypto-js@4.2.1
└─ RAT llama a servidor C2 (sfrclak[.]com)
└─ exfiltra credenciales, llaves SSH, variables de entornoEn dos segundos desde npm install, el malware ya estaba llamando al servidor del atacante — antes de que npm terminara de resolver dependencias. Cualquier máquina que ejecutó npm install con un rango flotante como ^1.14.0 fue comprometida.
Qué Previene Mentat
| Fase del Ataque | Sin Mentat | Con Sandbox Mentat |
| Ejecución del RAT | Corre con privilegios completos del usuario en el host | Corre dentro de namespace PID + mount + IPC. No puede ver procesos del host |
| Filesystem del host | Lectura/escritura completa a ~/.ssh, ~/.aws, /etc | pivot_root activo — filesystem del host invisible. RAT escribe al overlay, destruido al matar sandbox |
| Robo de credenciales | Lee llaves SSH, tokens AWS, variables de entorno | Secrets no se inyectan en fase de build. Entorno del sandbox es mínimo |
| Movimiento lateral | Puede hacer SSH a otras máquinas, escanear red | No ve procesos del host (PID NS). Con CLONE_NEWNET: sin egress |
| Persistencia | Escribe en crontab, .bashrc, systemd | Base es read-only overlayfs. Sandbox muere, RAT muere. Siguiente deploy parte limpio |
El Modelo de Bases: Inmunidad Completa
El sistema de bases overlayfs de Mentat provee una defensa más fuerte que solo el aislamiento en runtime. En vez de ejecutar npm installen cada deploy, las dependencias se graban en una base inmutable:
# Vulnerable: npm install corre en cada deploy
# RAT entra via postinstall hook
git push → npm install → build → deploy
↑
paquete malicioso se ejecuta aquí
# Inmune: base tiene deps fijos, deploy = solo código
base node22 = npm install con lockfile exacto (una vez)
git push → copia código al overlay → sin npm install → deploy
↑
no se ejecutan postinstall hooksSi la base fue construida antes del 31 de marzo con axios@1.14.0en el lockfile, y no se ejecuta npm install durante el deploy, la versión con backdoor nunca entra al sistema.
Capas de Defensa
| Capa 1 | Base inmutable | Dependencias fijadas al construir la base. Sin rangos flotantes |
| Capa 2 | Sin npm install en deploy | Deploy copia código al overlay, salta postinstall hooks completamente |
| Capa 3 | Namespace PID | RAT no puede ver ni señalizar procesos del host |
| Capa 4 | Namespace mount + pivot_root | Filesystem del host invisible. NO es chroot — enforcement a nivel de syscall |
| Capa 5 | Capabilities eliminadas | TODAS las capabilities Linux removidas. NO_NEW_PRIVS activado |
| Capa 6 | Límites cgroups v2 | Límites de memoria, CPU, PIDs. RAT no puede fork-bomb ni agotar recursos |
| Capa 7 | Namespace de red | CLONE_NEWNET + veth pair: RAT no puede alcanzar servidor C2. Tres modos: none (solo loopback), veth (NAT aislado), host (legacy) |
Las 7 Capas: En Produccion
Desde v1.0, las siete capas de aislamiento están implementadas y deployadas. El aislamiento de red (CLONE_NEWNET) usa veth pairs con iptables NAT para egress controlado. Los sandboxes de build usan network: none — solo loopback, sin ruta a internet. El RAT se ejecuta, no encuentra red, y muere silenciosamente.
Aun mas duro con Hull: allowlist de syscalls + Landlock + TCB de ~3 MB
El driver sandbox detiene al RAT en la frontera de namespaces + pivot_root. Correr el mismo workload Node.js en el driver Hull agrega tres capas mas que neutralizan directamente esta clase exacta de ataque:
| Allowlist seccomp-bpf | Hull instala un perfil node justo antes del execve: solo los syscalls que un proceso Node.js real necesita estan permitidos, todo lo demas gatilla KILL_PROCESS. Un RAT llamando a ptrace, process_vm_readv, bpf, add_key o userfaultfd esta muerto en el instante que lo intenta. Incluso socket(AF_NETLINK, ...) (usado para reconocimiento del host) esta bloqueado. |
| Landlock LSM | pivot_root esconde el host; Landlock va mas alla y confina al RAT dentro del rootfs del contenedor. Politica default: rootfs read+exec solamente, /tmp read+write, todo lo demas denegado. El RAT no puede dejar un archivo de persistencia en /opt/app/node_modules, no puede sobrescribir el binario de la app, ni siquiera puede hacer stat de otros directorios. |
| Modo --rootless | Con hull run --rootless el workload corre como uid 0 dentro de un NEWUSER mapeado a un uid no privilegiado del host. Incluso si el RAT de alguna forma escapa todas las otras capas, el uid del host donde cae no tiene escritura al filesystem del host, ni CAP_SYS_ADMIN, nada desde donde escalar. Defense in depth con cero sudo. |
| TCB minimo | Hull es un solo binario static-musl de ~3 MB. Sin dockerd, sin containerd, sin shim. Un CVE de escalacion local de privilegios en la toolchain de contenedores no tiene superficie de ataque aqui porque no hay daemon corriendo como root en primer lugar — hull termina apenas forkea el workload. |
En resumen: el driver sandbox evita que el RAT vea el host. Hull ademas evita que haga cosas que un workload Node.js normal nunca necesita hacer — incluso dentro de su propio contenedor.
Recomendaciones Prácticas
- Fijar versiones exactas en
package-lock.json. Nunca usar rangos^o~para deps de producción. - Construir bases con
npm ci(respeta lockfile exactamente). - Nunca inyectar secrets de producción en la fase de build.
- Deploy como overlay de solo código — sin
npm installal deployar. - Monitorear métricas de cgroups para picos anómalos de CPU/memoria durante builds.
- Rotar secrets inmediatamente si un build corrió durante la ventana de exposición.