Breeze Cache: unauthenticated arbitrary file upload (CVE-2026-3844)
Unauthenticated attackers can make affected Breeze Cache installations write arbitrary files through the remote Gravatar fetch. If PHP files can execute from the cache directory, the attacker can run code. Local Gravatar hosting must be enabled for this path.
Public CVE record · Vendor advisory or update instructions · Module source · Source and API bundle · CNA advisory
Patch title. Breeze Cache Upload Request Guard (breeze-cache-upload-request-guard in the registry). The original source snapshot preserves the source available for the historical report.
| Field | Value |
|---|---|
| Affected component and versions | Breeze Cache through 2.4.4 with local Gravatar hosting enabled |
| Fixed release | 2.4.5 |
| Severity | Critical (CVSS 3.1, 9.8, CNA) |
| Evidence status | Synthetic comparison only |
| Test environment | Synthetic HTTP fixture behind a single-node Eden 1.103.0 interlay |
| Tested Eden release and module | 1.103.0 · gabriel_breezeup_v1 1.0.0 |
| Registry package | breeze-cache-upload-request-guard 1.0.0 |
| Tested at | 2026-11-14 UTC |
| First publicly published | 2026-11-14T16:39:20Z |
Result. The marked request reached the synthetic backend in the baseline. Both protected configurations returned HTTP 403 for that request and the backend counter did not change. The native module passed the benign probe.
Synthetic HTTP controls
Tier 1 — declarative policy. The recorded policy denies every method on the recorded fixture route and its descendants. This is a coarse rule: it also blocked the benign probe on the same route, which is the recorded false positive.
{
"version": 1,
"profile": "http-structure-v1",
"policy": {
"version": 1,
"rules": [
{
"scope": {
"methods": [],
"path": "/wp-json/breeze",
"descendants": true
},
"require": {
"kind": "deny"
}
}
]
}
}
Tier 2 — native Rust module. The rule scans bodies under the /wp-json/breeze prefix for .php or phar:.
const ROUTE: &[u8] = b"/wp-json/breeze";
static MARKS: [&[u8]; 2] = [b".php", b"phar:"];
Implement the remediation
Vendor update. In WordPress, update Breeze Cache to 2.4.5 or later and confirm the installed version. If the upgrade must wait, disable local Gravatar hosting in Breeze’s advanced settings. Vendor instructions.
The published package uses registry name breeze-cache-upload-request-guard. Verify its own archive digest before import. Use the fixture API example to reproduce the recorded comparison. It covers the declaration, signed module activation, verification, revocation, and restoration.
Fixture and probes
The benign probe saved a clean text file. The marked probe uploaded a PHP payload. The fixture incremented its marker when an executable-named upload reached the write path.
Measured comparison (2026-11-14 UTC)
The values after each status are the observed increases in the fixture's effect counter.
| Probe | Baseline | Declarative policy | Native module |
|---|---|---|---|
| Benign clean file save | 200, 0 | 403, 0 | 200, 0 |
| Marked PHP upload | 200, 1 | 403, 0 | 403, 0 |
Test scope
The rule scans bodies under the /wp-json/breeze prefix for .php or phar:. The fixture did not run the plugin’s Gravatar fetch, write files, or execute PHP.
Signed module authority
Import returned HTTP 201 with explicit activation required and signature verification deferred. Read-only inspection was refused (403) for the reader principal, admission of a tampered statement was rejected (400), and admission of an invalid signature was refused (403). The activation receipt reported the module serving on all 32 expected shards. After revocation the marked probe received HTTP 503 (fail-closed); re-approval and reactivation restored the refusal (403, counter unchanged).
- Source SHA-256
5398f4e5ef7931a7b8d2b49bcc422cd150ad06473f284ec8c3597c1b6a66537b - Tested binary SHA-256
a5a5dd2850d20635ebdb2143b50f6d5c02761cbf07b81563219b7ae972e2bd2d - Activation operation
c6a472d9-7717-422d-9dc7-529271b16f46
Performance
Instrument: client wall-clock through the interlay (includes the network hop), warmup discarded, mean/p50/p95 in milliseconds.
| Arm | n | mean | p50 | p95 |
|---|---|---|---|---|
| Tier 1 — declarative policy, blocked | 15 | 0.4 ms | 0.4 ms | 0.6 ms |
| Tier 2 — module, benign passes (200) | 20 | 0.7 ms | 0.7 ms | 1.0 ms |
| Tier 2 — module, attack refused | 15 | 0.9 ms | 0.5 ms | 5.3 ms |