
Prova de conceito diferencial para CVE-2026-40176, demonstrando OS command injection no driver Perforce do Composer através de uma URL de repositório maliciosa, com teste A/B automatizado contra versões afetadas e corrigidas.
Uma prova de conceito autossuficiente, em estilo OOP em PHP, que demonstra e verifica diferencialmente uma vulnerabilidade de injeção de comandos no driver de repositório Perforce do Composer.
O PoC executa o mesmo composer.json malicioso contra duas versões do Composer — uma afetada (2.9.5) e uma corrigida (2.9.6) — e comprova a falha observando um efeito colateral (um arquivo marcador escrito por um comando shell injetado) que ocorre na versão afetada, mas não na corrigida.
⚠️ Apenas para pesquisa de segurança autorizada e testes defensivos. Consulte Uso Responsável.
| CVE | CVE-2026-40176 |
| Componente | Composer — driver de repositório/VCS Perforce (perforce) |
| Classe | Injeção de comandos do sistema operacional via URL de repositório controlada pelo atacante |
| Superfície de ataque | Um composer.json contendo uma entrada repositories manipulada com type: perforce |
| Afetada | Composer 2.9.5 |
| Corrigida | Composer 2.9.6 |
| Gatilho | Resolução/atualização de dependências (composer update) contra o manifesto malicioso |
| Impacto | Execução arbitrária de comandos na máquina que executa o Composer |
| Linguagem do PoC | PHP (arquivo único, sem dependências externas) |
O Composer pode resolver pacotes de vários sistemas de controle de versão. Para o Perforce, o repositório é identificado por uma URL p4:// que codifica o host, porta e usuário/stream. Quando o driver Perforce do Composer constrói a linha de comando p4 subjacente, campos retirados da URL controlada pelo atacante não são suficientemente sanitizados antes de serem passados para um shell.
Como o autor do manifesto controla completamente a URL do repositório, um atacante que consiga fazer uma vítima executar composer update/composer install contra um composer.json malicioso (por exemplo, uma dependência envenenada, um repositório hostil ou um job de CI processando arquivos de projeto não confiáveis) pode escapar da invocação pretendida do p4 e executar comandos arbitrários do sistema operacional com os privilégios do processo Composer.
Isso pertence à mesma família de problemas históricos de injeção de argumentos em drivers VCS do Composer, onde valores de URL/branch/stream fluem para comandos shell sem escape. O Composer 2.9.6 endurece o driver Perforce para que o payload injetado não seja mais executado.
A descrição autoritativa do comportamento demonstrado aqui é o próprio código-fonte do PoC (
CVE202640176Test.php); consulte o aviso oficial e o changelog do Composer para obter detalhes da correção upstream.
O PoC é uma única classe, CVE202640176Test, que realiza um experimento controlado A/B (diferencial) :
--version em ambas as versões do Composer (a afetada 2.9.5 e a corrigida 2.9.6) e aborta cedo se alguma não puder ser invocada.composer.json cuja seção repositories contém uma entrada perforce com uma URL p4:// maliciosa carregando um payload shell injetado.composer update nesse diretório.finally sempre restaura o composer.json original no diretório do projeto.PASS apenas quando a execução afetada mostra o efeito colateral e a execução corrigida não.Para cada execução, validateRun() verifica três coisas:
| Verificação | O que comprova |
|---|---|
| Arquivo marcador existe e contém o ID da execução | O payload touch/echo injetado realmente foi executado — ou seja, a injeção de comando foi bem-sucedida. |
A saída do Composer menciona p4 | O caminho do código do driver Perforce foi alcançado (o payload foi processado pelo componente correto, não por alguma etapa não relacionada). |
| Versão do Composer analisada == esperada | O binário correto (2.9.5 vs 2.9.6) foi o que foi executado. |
Uma execução é "OK" apenas quando todos os três passam. O teste geral passa quando a execução afetada é OK e a executada corrigida não é — a assinatura precisa de uma vulnerabilidade real que foi subsequentemente corrigida.
A URL maliciosa do repositório é construída em writeComposerJson():
p4://127.0.0.1:1666:attacker_user;touch <marcador> && echo '<runId>' > <marcador>:client_test
Detalhando:
p4://127.0.0.1:1666:attacker_user — uma URL Perforce com aparência bem formada (host, porta 1666, usuário).;touch <marcador> && echo '<runId>' > <marcador> — os comandos shell injetados. O ; inicial termina o comando p4 pretendido; touch cria o arquivo marcador, e echo '<runId>' > <marcador> escreve o ID único da execução nele para que o PoC possa confirmar que o payload (e não algum outro processo) produziu o arquivo.:client_test — texto adicional para manter o restante da análise da URL plausível.No driver afetado, os meta-caracteres do shell são respeitados e o arquivo marcador é criado. No driver corrigido, o valor é devidamente escapado/entre aspas, então a mesma string é tratada como dados inertes e nenhum marcador aparece.
Nota: o PoC usa um ID de execução único com timestamp e escreve seu marcador dentro de um diretório temporário isolado, portanto o payload é benigno e autolimpante, em vez de destrutivo.
2.9.5 (afetado)2.9.6 (corrigido)exec() executa cd … && php …). Projetado para Linux/macOS.composer.json base no diretório do projeto (ele é lido na inicialização, copiado para cada execução temporária e restaurado depois).Geralmente você não precisa de um servidor Perforce ativo: a vulnerabilidade está em como o Composer constrói a linha de comando
p4, e o payload injetado é executado antes/em torno de qualquer conexãop4real. O Composer pode registrar um erro de conexão Perforce — isso é esperado e não afeta a prova do arquivo marcador.
Clone / coloque o PoC em um diretório de trabalho.
Forneça um composer.json no mesmo diretório do PoC. Um mínimo é suficiente:
{
"name": "research/cve-2026-40176-poc",
"description": "Manifesto base para o PoC diferencial CVE-2026-40176",
"require": {}
}
Obtenha os dois binários do Composer e coloque-os onde o PoC espera (padrões mostrados):
/usr/local/bin/composer-2.9.5.phar # afetado
/usr/local/bin/composer-2.9.6.phar # corrigido
Você pode baixar versões específicas do Composer do arquivo oficial, por exemplo: