De 242 vulnerabilidades a cero en las imágenes del servidor de casa

Cada imagen que se sube al registro del servidor de casa se escanea sola con Trivy y deja un informe en las notas. El primer escaneo encontró 242 vulnerabilidades en las imágenes en uso; casi todas venían de las imágenes base. Así se dejaron a cero.

Todas las apps del hub, Vault y esta misma web corren en contenedores, y sus imágenes viven en Harbor, el registro de imágenes del servidor de casa. Harbor trae Trivy, un escáner que compara lo que hay dentro de cada imagen con las bases de datos públicas de vulnerabilidades. Hasta ahora nadie miraba sus resultados. Desde hoy, cada imagen se escanea sola al subirla y el resultado acaba en las notas, con una revisión y un arreglo.

Un informe por imagen, sin abrir Harbor

Cuando Trivy termina, Harbor avisa a n8n. n8n pide el informe, y si hay alguna vulnerabilidad escribe una nota en Markdown en la carpeta de notas del proyecto: qué imagen es, cuántas vulnerabilidades tiene de cada severidad, cuáles tienen versión arreglada y una sección «Revisión» vacía. Si el escaneo sale limpio, no escribe nada.

Cada nota pasa por tres estados: pendiente, en revisión y resuelta. Se revisa la causa, se corrige el repositorio y se sube la imagen nueva. Esa subida lanza otro escaneo. Solo cuando el escaneo nuevo confirma que las vulnerabilidades ya no están, la nota se completa con la causa, el arreglo, el commit y el escaneo que lo confirma, y se mueve a la carpeta de resueltas.

Hubo dos tropiezos al montarlo:

  • Harbor avisa con la imagen equivocada. Las imágenes se suben con varias arquitecturas, y el aviso trae la de arm64 sin etiqueta, no la que se subió. n8n tiene que buscar en el repositorio la imagen «madre» para saber de qué etiqueta se trata, y saltarse las firmas de compilación que también se suben.
  • Escanear todo de golpe genera ruido. La primera pasada incluyó las 111 imágenes del registro, también las etiquetas antiguas que se guardan para poder volver atrás: 106 informes. Solo 30 eran de imágenes que están en uso. Lo que importa es lo que corre.

De dónde venían las vulnerabilidades

Las imágenes en uso sumaban 242 vulnerabilidades, dos de ellas críticas. Casi ninguna estaba en el código de las apps.

Tabla con las vulnerabilidades por imagen antes y después: frontends del hub 6, APIs 1, asistente 2, web 6, Vault web 6 y buzón y señalización de Vault 88 cada una; después, cero en todas.
Vulnerabilidades por imagen antes y después del arreglo.
  • Los frontends (las ocho apps del hub, la web de Vault y esta web) se sirven con nginx:alpine. Cada uno tenía las mismas seis: librerías de Alpine (tiff, pcre2, libexpat, nghttp2, libpng y zlib) para las que ya había versión arreglada, pero la imagen base de Docker Hub aún no se había reconstruido con ellas.
  • Las APIs del hub ya actualizaban los paquetes al construirse, así que solo les quedaba un parche de zlib publicado después de la última compilación.
  • El asistente tenía además una vulnerabilidad alta en el SDK de MCP, la librería con la que habla con las herramientas del hub: en ciertas condiciones, un servidor MCP malicioso podía quedarse con las credenciales OAuth del cliente.
  • El buzón y la señalización de Vault tenían 88 cada uno, con la crítica de la librería tar. Ninguna era suya: venían del npm que trae la imagen de Node, que solo hace falta para instalar dependencias y que el servicio no usa nunca al ejecutarse.

Además, todas las imágenes de Node usaban la versión 20, que dejó de recibir parches de seguridad el 30 de abril.

El arreglo

  • Actualizar los paquetes de Alpine en la etapa final. Una línea, RUN apk upgrade --no-cache, justo después de FROM nginx:alpine. Así la imagen no depende de cuándo se reconstruye la base en Docker Hub. Se compila con --pull para partir siempre de la última.
  • Quitar npm de la imagen final. Después de instalar las dependencias se borran npm y corepack. El contenedor solo ejecuta node server.js. Las APIs del hub ya lo hacían; a Vault le faltaba.
  • Node 22 en todas las imágenes, también en las etapas que compilan las apps de Angular.
  • SDK de MCP a 1.31 o superior en el asistente y en el servidor de herramientas del hub.

Nada de esto cambia lo que hacen las apps, pero se comprobó antes de darlo por bueno. Se cargaron todos los módulos de las APIs con Node 22. Se levantó el servidor de herramientas del hub con el SDK nuevo para comprobar que sigue registrando sus 17 herramientas y respondiendo a una llamada. Y como el buzón de Vault compila una librería nativa para SQLite, se comprobó que abre su base de datos con la nueva versión de Node.

El orden fue el de siempre: primero el entorno de desarrollo y después producción. En producción no se reconstruye nada: se vuelven a etiquetar las mismas imágenes que ya se probaron, así que lo que corre es exactamente lo que se escaneó. El escaneo nuevo de todas las imágenes en uso salió con cero vulnerabilidades.

Lo que queda

Cero hoy no significa cero mañana: cada semana se publican vulnerabilidades nuevas en librerías que ya están dentro de las imágenes. Por eso lo importante no es el número, sino el ciclo: cada imagen nueva se escanea sola y, si sale algo, aparece una nota con lo que hay que revisar. Las imágenes que ya no se usan siguen en el registro con sus informes antiguos; toca decidir cuáles se borran.