flawopen.com/Incidents/gitlab-commits-api-path-traversal-september-2026
CVE-2026-85706: exposição de arquivos no GitLab
No GitLab, o parser de uploads podia selecionar arquivos sem autenticação; escapes inválidos expunham trechos em erros, sem divulgar o arquivo.[1], [3]
Imagine um atendente que aceita a localização de um armário escrita por um visitante em vez do documento na bandeja de entrada. Antes de conferir o crachá, ele abre o armário; se uma linha for ilegível, repete a linha em voz alta ao explicar o erro. Abrir o documento é uma falha; repetir seu conteúdo é outra.[1]
Conceitos Centrais e Termos
Upload metadata- O caminho file.path ou metadata.path fornecido na requisição não deve substituir um buffer registrado pelo processamento confiável de uploads.[1]
Percent decoding- Na análise de formulários, % seguido de dois dígitos hexadecimais é decodificado; uma sequência inválida pode produzir um erro que inclui o trecho problemático.[1]
CWE-22 / CVSS- O CNA classifica o
CVE-2026-85706como travessia de caminho, CVSS 10.0 Crítico. O limite violado é a seleção de arquivos do servidor controlada pelo solicitante.[3]
Mapeamentos de frameworks
- Referência CWE para a fraqueza descrita neste guia: CWE-22
- CISA KEV — adicionado em 2026-09-11 — CVE-2026-85706
Linha do Tempo do Incidente
O GitLab lançou 19.1.8, 19.2.6 e 19.3.2 com a correção de segurança.[2]
O aviso de lançamento passou a incluir as correções retroativas 18.11.12 e 19.0.9.[2]
Fluxo de Ataque Passo a Paso
Seleção antes da autenticação
Os metadados do upload podiam substituir o buffer temporário esperado por um caminho do servidor antes da autenticação.[1]
Conteúdo tratado como parâmetros
Com application/x-www-form-urlencoded, o arquivo selecionado era analisado como dados de formulário, não devolvido como resposta normal do commit.[1]
Reflexo no erro
Um escape percentual inválido podia inserir o trecho correspondente no erro. Os delimitadores & e = afetam a extensão; uma leitura isolada não prova divulgação.[1]
Investigação
Associe os registros da API Rails e do Workhorse por correlation_id; compare api_error com written_bytes para avaliar se bytes foram enviados na resposta.[1]
Código-Fonte: Vulnerável vs. Seguro
Modelo ilustrativo em Python, não é código nem correção do GitLab. O exemplo vulnerável usa apenas buffers em memória e trata qualquer % como erro, sem reproduzir a validação percentual real nem a escolha exata do trecho. A versão corrigida autentica antes de processar, rejeita metadados de caminho, aceita apenas bytes de um upload confiável, limita o tamanho e devolve erros genéricos. Instale a correção do fabricante: autenticar dentro da rota seria tarde se um middleware anterior já tivesse lido o arquivo.[1]
from urllib.parse import unquote_to_bytes
def parse_upload(authenticated, metadata, buffers):
# Fixtures inofensivos em memória; sem acesso ao sistema de arquivos.
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 vem do middleware de upload confiável,
# nunca de um caminho escolhido por parâmetros da requisição.
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 Verificação de Segurança para Engenharia
- ✓Atualize para uma versão corrigida e suportada. Os limites mínimos por ramo são 18.11.12, 19.0.9, 19.1.8, 19.2.6 e 19.3.2; os lançamentos afetados começam em 18.7. Confira a versão instalada no aviso oficial.[2], [3]
- ✓Teste requisições anônimas com marcadores inofensivos em memória: nenhuma busca de buffer antes da autenticação e nenhum marcador em respostas ou logs comuns. Rejeite metadados de caminho antes da análise.[1]
- ✓Preserve os logs da API Rails e do Workhorse; associe as entradas por
correlation_ide compareapi_errorcomwritten_bytes. Examine os valores decodificados de file.path e metadata.path em vez de excluir linhas inteiras com um caminho de upload benigno. Uma leitura não prova divulgação: segundo o GitLab, um trecho refletido em api_error, corroborado por written_bytes do Workhorse, indica bytes enviados; o status HTTP sozinho não é conclusivo.[1] - ✓Limite a rotação às credenciais incluídas na divulgação confirmada ou razoavelmente suspeita. Se
db_key_baseouotp_key_basepuderem estar envolvidos, consulte o suporte do GitLab antes de rotacioná-los: o GitLab informa que atualmente não há um caminho de rotação compatível paradb_key_basee alerta que uma rotação não compatível pode causar perda de dados. A ausência de logs não prova que não houve divulgação.[1]