El 17 de agosto GitLab publicó cuatro versiones fuera de calendario. El fallo que las motiva permite, bajo ciertas condiciones y sin necesidad de cuenta, modificar o borrar proyectos públicos. Cuando lo cuentas, la respuesta casi siempre es la misma: «el código lo tenemos clonado en todos los portátiles». Es verdad. Y es la parte que menos se pierde.
Cuatro versiones un lunes por la tarde
GitLab publicó el 17 de agosto de 2026 las versiones 19.2.4, 19.1.6, 19.0.8 y 18.11.11 como parche crítico, fuera del ciclo normal de actualizaciones de seguridad. Manda CVE-2026-19478, titulada «Code Injection issue via GraphQL directive impacts GitLab CE/EE», crítica, 9,4 de CVSS, con vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H. La descripción del fabricante, entera: «GitLab has remediated an issue that under certain conditions could allow an unauthenticated user to remotely modify or delete public projects and user data via a GraphQL directive». La reportó hiimguardian a través de HackerOne.
Afecta a CE y EE desde la 18.2 hasta antes de la 18.11.11, desde la 19.0 hasta antes de la 19.0.8, desde la 19.1 hasta antes de la 19.1.6 y desde la 19.2 hasta antes de la 19.2.4. En el mismo lote va CVE-2026-19650 (alta, 7,1), un CSRF en el manejador de consultas múltiples de GraphQL que «under certain conditions could have allowed an unauthenticated user to execute mutations via GET requests due to improper request validation». Este segundo necesita que alguien con sesión abierta pique —su vector lleva UI:R—, cosa que el primero no.
Dos cosas que conviene decir aunque desinflen el asunto. A 17 y 18 de agosto no consta explotación activa ni código de exploit público; quien venda urgencia con la expresión «activamente explotado» aquí, se la está inventando. Y «bajo ciertas condiciones» está en la frase original: GitLab no dice cuáles y nosotros no vamos a rellenar el hueco. Lo que sí es firme es a quién le toca trabajar. GitLab.com y GitLab Dedicated ya corrían la versión parcheada; para las instancias autoalojadas la instrucción es actualizar «immediately».
Lo que un clon no se lleva
El titular dice «borrar proyectos» y la cabeza va al código. Y el código es, de todo lo que hay dentro de un GitLab, lo único que está replicado por diseño: cada portátil del equipo tiene el árbol y la historia.
Con una excepción que se le escapa a casi todo el mundo: los runners no. GitLab CI clona en superficie por defecto, con profundidad 20. Lo que hay en la máquina que construye tu imagen son veinte commits.
| Está en cualquier clon | Vive solo en el servidor |
|---|---|
| Commits, ramas y etiquetas | Issues y su discusión |
| La historia completa del árbol | Merge requests, revisiones y aprobaciones |
El .gitmodules y el puntero del submódulo |
Variables de CI/CD y sus valores |
| Registro de contenedores y de paquetes | |
| Artefactos y logs de los jobs | |
| Wikis (repositorio git aparte) | |
Notas de git (refs/notes, no se clonan solas) |
|
| Protección de ramas, entornos, webhooks | |
| Miembros, permisos, tokens y runners registrados |
Dos filas de esa tabla merecen una nota. Las wikis son repositorios git independientes: nadie clona a mano proyecto.wiki.git, así que la documentación que el equipo escribió al lado del código está en el servidor y en ningún otro sitio. Y el submódulo: tu clon guarda un puntero de cuarenta caracteres, no el contenido, y el repositorio al que apunta puede ser otro de los que se acaban de borrar.
El daño de un borrado no se mide en repositorios. Se mide en por qué se decidió aquello, quién lo aprobó, con qué variable se despliega a producción y qué imagen exacta está corriendo ahora mismo. Nada de eso está en ningún portátil.
En junio hubo otro, y no llevaba CVE
Este es el precedente que casi ninguna cobertura del fallo de agosto menciona, y es el que mejor explica el problema de fondo. En junio, Yuhang Wu, de depthfirst, encadenó dos fallos de corrupción de memoria del analizador JSON Oj de Ruby a través del renderizado de diffs de cuadernos Jupyter, y consiguió ejecutar comandos en instancias autoalojadas. No hacía falta ser administrador: cualquier usuario autenticado que pudiera hacer push a un proyecto. Afectaba de la 15.2.0 a la 18.10.7, de la 18.11.0 a la 18.11.4 y de la 19.0.0 a la 19.0.1. Se corrigió el 10 de junio de 2026 en 18.10.8, 18.11.5 y 19.0.2, y la prueba de concepto se publicó el 24 de julio.
Sin CVE ninguno. Y aquí hay un detalle que es fácil contar mal, así que lo decimos completo: según The Hacker News, el propio investigador afirmó que depthfirst no pidió identificadores CVE para ninguno de los dos fallos, y GitLab no contestó a las preguntas de ese medio sobre por qué el arreglo no se clasificó como problema de seguridad. No hace falta suponer mala fe de nadie para llegar a la conclusión incómoda.
La conclusión es que si tu proceso de parcheo se dispara con los boletines de CVE, ese arreglo pasó por delante sin encender ninguna luz. Una instancia que se quedó en la rama 19.0 sin llegar a la 19.0.2 acumuló, entre junio y agosto, un camino a ejecución de comandos con una cuenta cualquiera y un borrado de proyectos sin cuenta. Ninguna de las dos cosas la habría avisado un lector de CVE. Sí la avisa saber en qué versión estás y compararla con la última, que es un trabajo mucho más aburrido. Es la misma disciplina que ya contamos hablando de nuestros despliegues: una etiqueta no es una versión.
La llave no está donde está la copia
Supongamos que pasa. gitlab-backup create hace más de lo que la gente cree: base de datos y su configuración, repositorios y objetos LFS, artefactos y logs de los jobs, ajustes de cuentas y grupos, registro de paquetes e imágenes del registro de contenedores, wikis de proyecto y de grupo, adjuntos y subidas, y algunas que sorprenden, como los estados de Terraform, el contenido de Pages y los snippets.
Y no incluye los ficheros de configuración de GitLab (/etc/gitlab, con gitlab.rb y gitlab-secrets.json), ni las claves y certificados TLS y SSH, ni Redis —y con él la cola de trabajos de Sidekiq—, ni los hooks globales de servidor y de fichero, ni el almacenamiento de objetos en instalaciones estándar por paquete, Docker o compiladas. Ese último merece aviso aparte: si tus artefactos, subidas, paquetes y objetos LFS viven en un bucket, tu copia de GitLab no los lleva dentro.
El que duele es gitlab-secrets.json, y conviene entender por qué con precisión. No es que ese fichero contenga tus variables de CI/CD: las variables están cifradas en la base de datos, que sí va dentro de la copia. Lo que contiene el fichero es la clave con la que se descifran. La documentación lo razona en una frase que debería estar colgada en más despachos: guardar la información cifrada en el mismo sitio que su clave anula el propósito de cifrarla. Y describe la consecuencia de perderla sin adornos: «Without the keys, multiple issues occur, including loss of access by users with two-factor authentication enabled, and GitLab Runners cannot sign in».
Un martes por la mañana eso se ve así: restauras, la base de datos entra entera, los repositorios están, la interfaz arranca, y las variables de despliegue son ilegibles, los runners no pueden iniciar sesión y la gente con segundo factor se queda fuera. Es primo hermano de una dependencia sobre la que ya escribimos: el servidor de copias que depende de aquello de lo que te protege.
Queda el otro requisito, en la misma documentación: «You can only restore a backup to exactly the same version and type (CE or EE) of GitLab on which it was created». La misma versión y la misma edición. De ahí sale un orden de operaciones que conviene tener escrito antes y no descubierto durante:
- Instalar la versión exacta —y la edición exacta— con la que se hizo la copia.
- Poner en su sitio los secretos y la configuración.
- Restaurar la copia.
- Y entonces actualizar a la versión parcheada.
El paso uno es incómodo de leer: si el desastre te pilla desactualizado, la ruta de vuelta pasa por levantar otra vez la versión vulnerable. No es motivo para no restaurar. Sí lo es para que esa máquina no esté publicada en Internet mientras dura la faena, y para que el paso cuatro esté en el mismo documento que el paso uno. Antes que todo eso hay una pregunta más tonta y más urgente: ¿qué versión exacta tenías anoche? Si no está escrita al lado del fichero de la copia, la restauración empieza con arqueología.
Qué haríamos esta semana
- Mirar la versión. En la interfaz,
/help. En instalación por paquete,sudo gitlab-rake gitlab:env:info. Anotarla —con la edición, CE o EE— donde se guarda la copia, no en la cabeza de nadie. - Actualizar a 19.2.4, 19.1.6, 19.0.8 o 18.11.11, según la rama.
- Contar los proyectos públicos de verdad, no los que uno recuerda. Si aparece ahí algo que no esperabas, ese es el hallazgo del día, con parche o sin él.
# Cuenta por páginas: 100 en la primera página significa que hay más
for p in $(seq 1 20); do
n=$(curl -s "https://TU-GITLAB/api/v4/projects?visibility=public&simple=true&per_page=100&page=$p" | jq 'length')
echo "page $p: $n"; [ "$n" -lt 100 ] && break
done
- Decidir qué tiene que verse desde Internet: la instancia entera, el listado público de proyectos, ninguna de las dos. En diciembre de 2024 Cycode localizó con Shodan más de 40.000 servidores GitLab autoalojados; el número tiene año y medio y la costumbre sigue igual.
- Sacar los secretos de la máquina.
gitlab-secrets.jsonygitlab.rbfuera, cifrados, con la misma disciplina que la copia grande. En el mismo disco que GitLab no son una copia. - Ensayar la restauración en una máquina limpia hasta ver un pipeline en verde. No hasta que arranque la interfaz: hasta que un job real termine bien y un runner haya podido iniciar sesión.
- Mirar dónde está el almacenamiento de objetos. Si está fuera, se copia aparte y se escribe en el mismo documento, porque el día malo nadie se acuerda.
Lo que no vamos a recomendar
Irse al servicio gestionado por esto. GitLab.com estaba parcheado antes de que nadie se enterara, y como argumento es honesto y hay que reconocerlo. Pero mudar una plataforma entera para no tener que aplicar parches es cambiar un trabajo que conoces por otro que todavía no; y las razones por las que alguien se autoaloja —dónde vive el código, con qué se integra, qué cuesta— no las deroga un boletín de seguridad.
Meterlo entero detrás de la VPN sin mirar. Es la reacción refleja y a veces es la correcta, pero rompe cosas que alguien está usando ahora mismo: webhooks entrantes, runners externos, integraciones de terceros, páginas publicadas. Si se hace, se hace con la lista de lo que se rompe delante y avisando a quien la use, que es más trabajo que teclear una regla de cortafuegos. Es la misma cadena de detalles pequeños de la que hablábamos al repasar cómo se cuela un secreto en un pipeline.
Y toca declarar el conflicto de interés, porque aquí no hablamos desde la grada: usamos GitLab autoalojado para nuestro propio CI/CD y para desplegar esta misma web. La lista de arriba nos la aplicamos nosotros, con el mismo calendario y las mismas prisas.
Dos preguntas que no hace falta contestar en público
La herramienta con la que se despliega todo lo demás es, en casi todas las empresas que conocemos, la única que no tiene ventana de mantenimiento propia, ni plan de restauración escrito, ni ensayo. Se actualiza cuando no molesta, que es nunca, porque siempre hay alguien desplegando.
Así que dos preguntas, y no hay que contestarlas en voz alta: ¿cuánto tarda tu equipo en parchear la herramienta con la que despliega el resto? Y, sin ir a mirar: ¿qué versión exacta habría que instalar para poder restaurar la copia de anoche?
Fuentes (verificadas el 19 de agosto de 2026): las versiones publicadas el 17 de agosto de 2026, los identificadores CVE-2026-19478 y CVE-2026-19650, sus títulos, gravedades, puntuaciones y vectores CVSS, las descripciones citadas literalmente, los rangos de versiones afectadas, los reporteros hiimguardian y kreep, la recomendación de actualizar «immediately» y que GitLab.com y GitLab Dedicated ya corrían la versión parcheada, de GitLab Docs, «GitLab Critical Patch Release: 19.2.4, 19.1.6, 19.0.8, 18.11.11». La ausencia de explotación conocida y de exploit público a 17-18 de agosto, de la cobertura de The Hacker News. Qué incluye y qué no incluye el archivo de copia, de «Back up GitLab»; el requisito de restaurar sobre la misma versión y edición y la frase sobre las claves, de «Restore GitLab». La cadena de junio (Yuhang Wu / depthfirst, analizador Oj y diffs de cuadernos Jupyter), las versiones afectadas y corregidas el 10 de junio de 2026, la publicación de la prueba de concepto el 24 de julio, que depthfirst no pidió identificadores CVE y que GitLab no respondió a las preguntas sobre la clasificación del arreglo, de The Hacker News. Los más de 40.000 servidores GitLab autoalojados localizados con Shodan, de Cycode Labs, publicado el 15 de diciembre de 2024 y citado con su fecha. La profundidad de clonado por defecto de GitLab CI (20) y que las wikis son repositorios git independientes, de la documentación de GitLab. Son nuestros: la lectura de que lo que se pierde en un borrado es el contexto y no el código, la tabla de qué está en un clon y qué no, el orden de operaciones de la restauración, la tesis de que parchear siguiendo boletines de CVE deja fuera arreglos sin CVE, la lista de comprobaciones y las dos posiciones de «lo que no vamos a recomendar». Las citas de GitLab se dejan en inglés, su idioma original, para que se puedan verificar palabra por palabra.
¿Cuándo se probó por última vez esa restauración?
En los planes de disaster recovery que escribimos, el ensayo de restauración va con fecha y con resultado, no con buena voluntad. Y cuando nos hacemos cargo de la infraestructura y el cloud de alguien, el inventario de versiones es de lo primero que ponemos por escrito, porque es lo que decide cuánto dura un mal día.
Hablar con everyWAN