flawopen.com/Incidents/gitlab-commits-api-path-traversal-september-2026
CVE-2026-85706: exposición de archivos en GitLab
El parser de GitLab podía elegir archivos sin autenticar; escapes inválidos mostraban fragmentos en errores, pero elegir no divulgaba archivos.[1], [3]
Imagina a un recepcionista que acepta la ubicación de un armario escrita por un visitante en lugar del documento de la bandeja de entrada. Antes de comprobar su identificación, abre ese armario; si no puede interpretar una línea, la repite en voz alta al explicar el error. Abrir el documento es un fallo; repetir su contenido es otro.[1]
Conceptos Clave y Términos
Upload metadata- Los parámetros file.path o metadata.path enviados por el cliente no deben sustituir un búfer registrado por el sistema de carga de confianza.[1]
Percent decoding- Al analizar formularios, % seguido de dos dígitos hexadecimales se decodifica; una secuencia inválida puede producir un error que incluya el fragmento problemático.[1]
CWE-22 / CVSS- La autoridad CNA clasifica
CVE-2026-85706como recorrido de rutas, CVSS 10.0 Crítico. El límite vulnerado es la selección de archivos del servidor controlada por el solicitante.[3]
Mapeos de marcos
- Referencia CWE para la debilidad descrita en esta guía: CWE-22
- CISA KEV — añadido el 2026-09-11 — CVE-2026-85706
Cronología del Incidente
GitLab publicó 19.1.8, 19.2.6 y 19.3.2 con la corrección.[2]
El aviso se actualizó para incluir las versiones corregidas 18.11.12 y 19.0.9.[2]
Flujo de Ataque Paso a Paso
Selección antes de autenticar
Los metadatos de carga podían sustituir el búfer temporal esperado por una ruta del servidor antes de autenticar.[1]
Contenido convertido en parámetros
Con application/x-www-form-urlencoded, el archivo elegido se interpretaba como formulario; no se devolvía como respuesta normal de una confirmación.[1]
Reflejo en el error
Un escape de porcentaje inválido podía incluir el fragmento defectuoso en el error. Los separadores & y = delimitaban su tamaño; leer no implica divulgar.[1]
Investigación
Correlacione los registros de la API de Rails y Workhorse mediante correlation_id; compare api_error con written_bytes para evaluar si se enviaron bytes en la respuesta.[1]
Código Fuente: Vulnerable vs. Seguro
Modelo ilustrativo en Python, no es código ni parche de GitLab. El ejemplo vulnerable solo usa búferes en memoria y trata cualquier % como error, sin reproducir la validación real ni la selección del fragmento. El modelo corregido autentica primero, rechaza metadatos de ruta, admite solo bytes registrados por un componente fiable, limita su tamaño y devuelve errores genéricos. Aplique la actualización del proveedor: autenticar dentro de la ruta llega demasiado tarde si un componente previo ya leyó el archivo.[1]
from urllib.parse import unquote_to_bytes
def parse_upload(authenticated, metadata, buffers):
# Fixtures inocuos en memoria; sin acceso al sistema de archivos.
body = buffers.get(metadata.get("path"), b"")
if b"%" in body:
return 400, body.decode("ascii", errors="replace")
if not authenticated:
return 401, "Unauthorized"
return 200, unquote_to_bytes(body)
from urllib.parse import unquote_to_bytes
MAX_BYTES = 4096
HEX = frozenset(b"0123456789abcdefABCDEF")
def parse_upload(authenticated, metadata, registered_body):
# registered_body proviene de middleware de carga confiable,
# nunca de una ruta elegida por parámetros de la solicitud.
if not authenticated:
return 401, "Unauthorized"
if metadata or type(registered_body) is not bytes:
return 400, "Invalid upload"
if len(registered_body) > MAX_BYTES:
return 413, "Upload too large"
for i, byte in enumerate(registered_body):
if byte == 37 and (i + 2 >= len(registered_body) or
registered_body[i+1] not in HEX or
registered_body[i+2] not in HEX):
return 400, "Invalid upload"
return 200, unquote_to_bytes(registered_body)
Lista de Verificación de Seguridad para Ingeniería
- ✓Actualice a una versión corregida y compatible. Los mínimos por rama son 18.11.12, 19.0.9, 19.1.8, 19.2.6 y 19.3.2; las versiones afectadas empiezan en 18.7. Compruebe la versión instalada en el aviso oficial.[2], [3]
- ✓Pruebe solicitudes anónimas con marcadores inocuos en memoria: ninguna búsqueda de búfer antes de autenticar y ningún marcador en respuestas o registros ordinarios. Rechace metadatos de ruta antes de analizarlos.[1]
- ✓Conserve los registros de la API Rails y Workhorse; correlacione las entradas mediante
correlation_idy compareapi_errorconwritten_bytes. Inspeccione los valores decodificados de file.path y metadata.path en vez de descartar líneas enteras por contener una ruta de carga benigna. Una lectura no demuestra divulgación: GitLab indica que un fragmento reflejado en api_error, corroborado por written_bytes de Workhorse, evidencia bytes enviados; el estado HTTP por sí solo no es concluyente.[1] - ✓Limite la rotación a las credenciales incluidas en una divulgación confirmada o razonablemente sospechada. Si pueden estar implicados
db_key_baseuotp_key_base, consulte al soporte de GitLab antes de rotarlos: GitLab indica que actualmente no existe una vía de rotación compatible paradb_key_basey advierte que una rotación no compatible puede causar pérdida de datos. La falta de registros no demuestra que no hubiera divulgación.[1]