- Em sistemas do tipo Unix, clonar um repositório não confiável com
git clone --recursive pode permitir execução remota de código via CVE-2025-48384, exigindo atualização do Git e de softwares que incorporam Git
- A causa é a diferença no tratamento de carriage return (
\r) durante a leitura e regravação de configurações do Git, fazendo com que o valor validado e o valor realmente usado fiquem divergentes
- Se for inserido
\r no fim do path de um submódulo em .gitmodules, o caminho de checkout pode mudar para outro caminho após a validação
- O Windows não é diretamente vulnerável porque não permite caracteres de controle em nomes de arquivo, mas o macOS é vulnerável tanto ao CVE-2024-32002 quanto ao CVE-2025-48384
- O patch passa a colocar entre aspas os valores de configuração que contêm
\r, bloqueando vetores de ataque como gravação de arquivos dentro de .git e criação de hooks do Git
Visão geral da vulnerabilidade e ação imediata
- CVE-2025-48384 é uma vulnerabilidade do Git que pode levar à execução remota de código ao clonar um repositório não confiável com
git clone --recursive em plataformas do tipo Unix
- É necessário atualizar para as versões corrigidas do Git e também atualizar softwares que incorporam Git, incluindo o GitHub Desktop
- Ao executar apenas
git clone na linha de comando, os submódulos não são clonados automaticamente
- Como mitigação, é possível primeiro executar
git clone sem --recursive, verificar se .gitmodules é seguro e só então inicializar os submódulos
- O GitHub Desktop faz clone com a opção recursiva por padrão, então pode ser afetado nesse comportamento
Carriage return e arquivos de configuração do Git
- Carriage return é o caractere ASCII número 13, Carriage Return, representado como
\r em strings C
- O Unix tentou usar apenas LF, isto é,
\n, para separar linhas, mas o Windows e vários protocolos da internet usam CR+LF, ou seja, \r\n
- O formato de configuração estilo
.ini do Git é usado não só em arquivos de configuração do usuário, mas também no arquivo .gitmodules incluído no repositório
- Para dar suporte a finais de linha do DOS, o parser de configuração do Git funciona assim ao ler caracteres
- Se o caractere atual for
\r, ele verifica o próximo caractere
- Se o próximo caractere for
\n, descarta o \r e trata como quebra de linha
- Se o próximo caractere não for
\n, devolve o próximo caractere ao fluxo e retorna o próprio \r
- Esse tratamento é aplicado linha por linha, então se alguma linha terminar com CR, esse CR pode ser removido independentemente do formato do restante do arquivo
Inconsistência entre leitura e escrita
- O Git não apenas lê arquivos de configuração, mas também grava pares
key = value ao escrever valores de configuração, como em git config
- O código antigo só colocava o valor entre aspas duplas ao regravar a configuração nos casos abaixo
- Quando o valor começava com espaço
- Quando havia
; ou # dentro do valor
- Quando o valor terminava com espaço
- Já o código de leitura da configuração aceita strings entre aspas, então um valor escrito por
write_pair podia ser relido mais tarde com o \r final removido
- Por exemplo, se o arquivo de configuração contiver
key = "foo^M", após ser regravado ele pode virar key = foo^M
- Aqui
^M representa um caractere CR literal
- Quando esse comportamento se combina com um valor não confiável de
.gitmodules, o tratamento do caminho do submódulo fica inconsistente
Confusão no caminho do submódulo e escopo do impacto
- Em sistemas baseados em Unix, é possível colocar caracteres de controle em nomes de arquivo, então dá para inserir um valor com CR no
path de .gitmodules
- O exemplo tem a seguinte forma
[submodule "foo"]
path = "foo^M"
- Se esse valor for gravado pelo código de configuração do Git em
.git/modules/foo/config, ele pode ficar assim
[core]
workdir = ../../../foo^M
- A validação do caminho não confiável lido de
.gitmodules já terá sido concluída nesse ponto
- Depois, ao reler a configuração, o
\r final é removido e o Git passa a usar um caminho diferente do que foi validado
- Como resultado, durante a clonagem do submódulo, o local lido em
path = ... pode diferir do local realmente gravado e usado
- Esse princípio é semelhante ao do CVE-2024-32002
- O CVE-2024-32002 confundia o Git explorando a distinção entre maiúsculas e minúsculas em submódulos
- O CVE-2025-48384 exige um sistema de arquivos que permita caracteres de controle em nomes de arquivo
- O Windows não é diretamente vulnerável a esse bug específico porque não permite caracteres de controle em nomes de arquivo
- O macOS é vulnerável tanto ao CVE-2024-32002 quanto ao CVE-2025-48384
Patch e possibilidade de exploração
- O patch altera
write_pair para colocar o valor entre aspas quando ele contém \r
- A mudança é simples: adiciona
'\r' à condição que antes verificava apenas ; ou #
for (i = 0; value[i]; i++)
- if (value[i] == ';' || value[i] == '#')
+ if (value[i] == ';' || value[i] == '#' || value[i] == '\r')
quote = "\"";
- Com a confusão de caminhos, arquivos maliciosos do submódulo podem ser colocados em posições quase arbitrárias no sistema de arquivos e, como a validação é contornada, links simbólicos fora do repositório também podem ser seguidos
- A forma de exploração mais direta é gravar arquivos dentro do diretório
.git e criar um script de hook do Git, fazendo com que código controlado pelo atacante seja executado quando o Git rodar o hook
- Outra possibilidade é sobrescrever
.git/config
- Um PoC ainda não foi publicado, mas foi dito que bastaria uma modificação quase trivial no exploit do CVE-2024-32002
- Os testes do commit de correção podem dar fortes pistas sobre a forma de ataque
O problema recorrente do CR e a lição
- Não é a primeira vez que carriage return causa problemas no Git
- Em janeiro, RyotaK descobriu um problema no protocolo do credential helper que podia ser enganado com carriage return
- Em 2023, André Baptista e Vítor Pinho descobriram o CVE-2023-29007, uma falha lógica no parsing de configuração
- Essa vulnerabilidade não é um problema da linguagem C em si, mas sim um erro lógico que pode surgir em praticamente qualquer linguagem
- O ponto em comum é que ela ocorre em comunicação entre processos entre componentes internos do Git ou entre o Git e processos externos
- Há uma estrutura parecida com HTTP CRLF injection, request smuggling e SMTP smuggling
- No passado, a internet dependia do princípio de robustez de Postel — “seja conservador ao enviar e liberal ao receber” —, mas talvez essa já não seja a recomendação mais sensata
- O tema é tratado com mais detalhes no RFC 9413
Agradecimentos e correções relacionadas
- Essa vulnerabilidade foi descoberta durante uma auditoria do Git
- Na mesma release, também foram corrigidos outros bugs com diferentes níveis de severidade
- A G-Research Open Source tornou esse trabalho possível
Ainda não há comentários.