📻 Versión en audio: si prefieres escuchar en vez de leer, el resumen del artículo está justo aquí arriba.
El 12 de octubre GitLab publicó el parche de CVE-2026-97229: crítico, CVSS 10.0, en cómo evalúa expresiones regulares dentro de la configuración de CI. Nueve días después, un atacante con una cuenta recién creada golpeó el GitLab de Alpine Linux con configuraciones armadas para explotarlo. Tiró procesos de trabajo ocho veces y, en cuatro de esas caídas, el exploit avanzó un tramo antes de fallar en el siguiente. Nunca pudieron confirmar que el código enemigo no corrió en el servidor, así que cerraron todo y reconstruyeron la instancia desde cero. Y acá viene lo que más me hizo pensar: el servidor había sido actualizado.
El bug no estaba donde decía el boletín
El CVE apunta a GitLab, pero el defecto de fondo vive en Onigmo, el motor de expresiones regulares que Ruby lleva incorporado. GitLab evalúa regex que vienen en los archivos de CI, o sea input no confiable que sube cualquier usuario con cuenta. El arreglo de GitLab no tocó su propio código: son parches sobre el Ruby que trae embebido en sus paquetes e imágenes oficiales. El fix en Ruby upstream llegó recién el 23 de octubre, en las versiones 3.3.13, 3.4.12 y 4.0.9.
Dos errores encadenados
El primero, humano y de manual: el 13 de octubre, un día después del aviso, actualizaron su GitLab, pero instalaron 19.3.4 en vez de 19.3.5, que era el que traía el parche. Un punto de versión de por medio, y ahí golpearon los días 20 y 21. Además, el atacante descargó la imagen de contenedor del GitLab de Alpine: en la práctica, estuvo estudiando el build exacto que corrían para afinar el exploit a su medida.
El segundo es el que me importa: el 22 subieron a 19.3.6, la versión ya corregida, y la instancia siguió vulnerable. Su imagen usaba Ruby estándar, sin los parches que GitLab aplica solo en sus builds oficiales. Parchear el paquete no parcheó la dependencia. Lo detectaron el 26, y al día siguiente cerraron el GitLab y arrancaron la reconstrucción. Si usas el contenedor alpinelinux/gitlab: cualquier imagen 19.3.6 bajada antes del 27 de octubre sigue vulnerable, y las etiquetas más antiguas también.
Asumir el peor caso, con evidencia incompleta
Lo que más respeto del manejo de Alpine es que reconstruyeron todo sin poder demostrar el compromiso. La razón es incómoda: un exploit exitoso de esta clase no deja crash ni rastro en los logs web, los logs del día del ataque se perdieron, nadie registraba conexiones salientes —ni ellos ni su proveedor— y retenían logs por solo 14 días. Con evidencia incompleta, el único camino defendible es tirar el terreno: instancia nueva, llaves secretas reemplazadas, todos los passwords reseteados. De paso verificaron que ni los paquetes ni los releases de octubre habían sido manipulados, contrastando commits de aports contra copias fuera del GitLab, y confirmaron que las llaves de firma nunca estuvieron en ese servidor.
Los cambios que se llevan son puro oro para cualquiera que administre servicios: parches críticos en menos de 24 horas revisando de qué componentes viene cada release, logs de conexiones salientes, retención más larga, y tags de releases firmados para no depender de la plataforma que acaba de ser el blanco.
Mi conclusión: cuando administras servicios con imágenes de terceros, «actualicé» es una frase vacía hasta que sabes qué trae adentro el contenedor que corre en producción. El parche puede estar en el paquete, en la dependencia embebida, o en lo más probable, en ninguno de los dos. Preguntárselo una vez por release es más barato que reconstruir una instancia entera a ciegas. Y si no sabes la respuesta, ese silencio también es información: es exactamente lo que el otro lado está esperando.
Fuente de inspiración: GitLab security incident: attempted exploitation of CVE-2026-97229