- Se detectó un uso anormal de CPU en un servidor de Hetzner operado de forma personal y, al investigarlo, se descubrió que estaba ejecutándose un programa de minería de criptomonedas Monero (
xmrig)
- La causa fue que el contenedor de la herramienta de analítica Umami fue comprometido, incluyendo una vulnerabilidad de ejecución remota de código en Next.js (CVE-2025-66478)
- Afortunadamente, como ese contenedor se ejecutaba con un usuario no root y no tenía montajes del host ni escalamiento de privilegios, la intrusión quedó limitada al interior del contenedor
- El atacante aprovechó la deserialización insegura de los Server Components de Next.js para ejecutar una carga maliciosa e instalar el minero
- Este caso muestra la importancia de la gestión de dependencias y de la configuración de seguridad de contenedores, y el autor reforzó sus medidas de seguridad activando el firewall, endureciendo SSH y aplicando actualizaciones periódicas
El incidente y la respuesta inicial
- Se recibió de Hetzner un correo de advertencia indicando que el servidor había escaneado redes externas
- Incluía el aviso de que el servidor podía ser bloqueado si no se actuaba en un plazo de 4 horas
- Al revisar por SSH, se encontró un proceso usando 819% de CPU en la ruta
/tmp/.XIN-unix/javae, junto con varios procesos xmrig
- Se confirmó que la minería de criptomonedas llevaba aproximadamente 10 días en marcha
Investigación de la vía de intrusión
- Todos los procesos maliciosos se estaban ejecutando con el usuario UID 1001, lo que coincidía con el contenedor de Umami
- Se encontró el binario del minero en el directorio
/app/node_modules/next/dist/server/lib/xmrig-6.24.0/
- El comando de ejecución incluía la dirección del pool de minería
auto.c3pool.org:443 y una clave de usuario
La vulnerabilidad de Next.js y el método de ataque
- La causa fue la vulnerabilidad de deserialización de React Server Components en Next.js (CVE-2025-66478)
- Si un atacante enviaba una solicitud HTTP manipulada, podía ejecutar código arbitrario en el servidor
- Como resultado, era posible instalar y ejecutar un minero de criptomonedas
- El autor pensaba que “no usaba Next.js directamente”, pero más tarde se dio cuenta de que Umami está basado en Next.js
Verificación del aislamiento del contenedor
- Se confirmó que
/tmp/.XIN-unix/javae no existía en el sistema de archivos del host
- Solo era un efecto de que la salida de
docker ps muestra procesos del contenedor; en la práctica, el aislamiento se mantenía
- Resultado de
docker inspect
- Usuario:
nextjs
Privileged: false
Mounts: ninguno
- Por lo tanto, el malware no pudo acceder al host, registrar tareas cron, crear servicios del sistema ni instalar rootkits
Recuperación y refuerzo de seguridad
- Tras detener y eliminar el contenedor infectado de Umami, el uso de CPU volvió a la normalidad
- Se activó el firewall UFW para permitir solo SSH, HTTP y HTTPS
- Después de reportar a Hetzner el resultado de la investigación, el ticket se cerró en menos de 1 hora
Lecciones y mejoras
- Decir “yo no uso X” no incluye necesariamente las dependencias
- Hay que revisar con qué stack tecnológico están construidas las herramientas que se usan
- Se demostró la eficacia del aislamiento de contenedores
- Ejecutar con usuario no root, en modo no privilegiado y sin volúmenes innecesarios evitó que el daño se propagara
- Es necesaria una defensa en profundidad (Defense in Depth)
- Firewall, fail2ban, monitoreo y actualizaciones periódicas son esenciales
- Se enfatiza la importancia de escribir el Dockerfile directamente y de minimizar los privilegios del contenedor
Medidas tomadas después del incidente
- Se volvió a desplegar Umami con la versión más reciente y se auditaron todos los contenedores de terceros
- Se revisaron el usuario de ejecución, los montajes, el momento de actualización y la necesidad de cada uno
- Se cambió a autenticación con clave SSH, se deshabilitó el inicio de sesión por contraseña y se configuró fail2ban
- Se reforzó el monitoreo con Grafana y Node Exporter y se aplicaron de inmediato las actualizaciones de seguridad
Conclusión
- Aunque la vulnerabilidad de Next.js en Umami permitió que se usara el sistema para minar Monero durante 10 días, el aislamiento del contenedor y la ejecución sin root limitaron el impacto
- A través de esta experiencia, el autor internalizó la importancia de conocer las dependencias, configurar la seguridad y gestionar las actualizaciones
- El incidente se contuvo en unas 2 horas y quedó como un caso real que validó la eficacia práctica de la seguridad en contenedores
1 comentarios
Comentarios de Hacker News
Antes recomendaba UFW, pero ahora recomiendo firewalld
UFW se vuelve difícil de administrar con el tiempo, mientras que firewalld es mucho más estable gracias a su configuración basada en XML
Con el comando
firewall-cmdse puede configurar SSH, HTTPS, el puerto 80, etc., y conviene usar el backend de nftablesEn el caso de Docker, a menudo termina abriendo puertos saltándose las reglas del firewall, así que es más seguro configurar
StrictForwardPorts=yesen/etc/firewalld/firewalld.conf8080:8080, es mejor hacer bind a una IP privada como192.168.0.1:8080:8080Yo corro Docker en una VM 10.0.10.11, accesible solo por WireGuard, y me resultó práctico poner Caddy como proxy inverso
El malware intentará conectarse a un pool de minería externo o a un servidor C2, así que hay que bloquear el acceso a la red de binarios no autorizados
También sirve quitar permisos de ejecución de
/tmp,/var/tmpy/dev/shmnftables.confpor sí solo ya queda todo suficientemente simple y claroiptables ya está deprecado, así que no hace falta una capa extra como firewalld
Esto parece estar relacionado con “React2Shell CVE-2025-55182”
Es raro que una vulnerabilidad que lleva más de un año afectando a sistemas casi no haya recibido atención
Si desplegaste una web app con Next.js en los últimos 12 meses, es muy probable que ya forme parte de una botnet
Frustra que la industria solo dé consejos del tipo “usa Docker” o “enciende el firewall”
Últimamente me siento tan escéptico con el ecosistema frontend que estoy pensando en mover mi carrera hacia C++
Hoy la combinación Next.js, React, Tailwind y Postgres lleva 5 años consolidada casi como estándar
Comparado con la época de explosión de frameworks de finales de los 2000 y principios de los 2010, ahora es bastante estable
Si no te gustan las modas y el cambio, el desarrollo de IA cambia mucho más rápido
En backend puedes usar un stack tecnológico sólido como .NET, Java o Go, y elegir el frontend con más libertad
Así reduces CVEs y también el cansancio tecnológico
Discusión relacionada en GitHub
Si limitas el uso de CPU de un contenedor Docker con
--cpus="0.5", un servicio con fallas o un minero no afecta a todo el sistemaOperar un servidor sin firewall es una decisión bastante audaz
Si además usas el firewall externo de Hetzner, tienes una capa de defensa extra por si cometes un error
Yo permito SSH solo desde la IP de mi casa, y cuando lo necesito desde fuera, lo habilito temporalmente desde el sitio web de Hetzner
Lo realmente importante es no ejecutar software con vulnerabilidades RCE
Que Docker pareciera haber sido el salvador fue, en realidad, solo cuestión de suerte
En cambio, se puede usar un bastion host y controlar entrada y salida con un proxy HTTP, pero configurarlo es complejo
Usar puertos no estándar resultó sorprendentemente efectivo
No sé qué tan efectivo sea, pero se siente como una especie de paraguas psicológico
Me preguntaba si al correr un contenedor Docker como root también se podía atacar al host
Si quieres correr código no confiable, debes usar una VM (KVM/QEMU) o tecnologías como gVisor(https://gvisor.dev/) y Firecracker(https://firecracker-microvm.github.io/)
Docker debe entenderse más como un entorno de ejecución aislado que como un sandbox
La configuración por defecto de Docker no limita RAM, CPU ni uso de disco, así que también es vulnerable a ataques DoS
Además, muchas guías recomiendan opciones riesgosas como
--privilegedoCAP_SYS_PTRACETambién es posible levantar un contenedor nuevo y escalar a privilegios de root
Docker todavía no lo trae como valor por defecto, así que si no lo configuras, el riesgo de escape es alto
En el pasado, la mayoría de los escapes de contenedores podrían haberse evitado con user namespace
Si el servidor no maneja datos sensibles, muchas veces basta con limpiar el contenedor
Para reducir la superficie de ataque, no deberías exponer al exterior servicios que no necesitan ser públicos
Por ejemplo, se puede hacer que una herramienta de analítica sea accesible solo mediante WireGuard o un proxy SOCKS por SSH
Yo también sufrí una infección con un minero de Monero en un servidor de Hetzner
Por suerte ocurrió solo dentro de un contenedor LXC de Incus, y como la prioridad de CPU era baja, no me di cuenta
Se había agregado una clave SSH a la cuenta root y se había instalado un agente de administración remota
Al final descarté el contenedor, pero me dejó varias lecciones
El artículo incluía contenido de alucinaciones de IA no corregido por una persona
Repite que era una vulnerabilidad relacionada con Puppeteer, pero eso no es cierto
Últimamente están instalando mineros de Monero por todos lados explotando una vulnerabilidad de React 19
A mí también me pasó lo mismo
Funciona como una especie de bug bounty automático, porque te avisa que tienes una vulnerabilidad
Si tienes buen monitoreo de red o procesos, se detecta fácilmente
Gracias a eso tuve una buena oportunidad para mejorar mi sistema de backups
Casos como este me hacen pensar que hice bien en no seguir administrando VPS por mi cuenta
Ya lo intenté antes, pero siento que estoy en un nivel de administrador promedio y mantener la seguridad se me hace difícil
Por eso ahora prefiero dejarlo en manos de expertos y pagar el costo, porque me da mucha más tranquilidad