This is a valet key hidden in the storefront cookie jar
CVE-2026-45247 is a PHP object injection bug in Mirasvit Full Page Cache Warmer for Magento 2 that affects all versions before 1.11.12. The extension reads a client-supplied CacheWarmer cookie on ordinary storefront requests and passes attacker-controlled data into PHP unserialize(). Because Magento and its dependencies provide usable gadget chains, this is not just theoretical deserialization noise; it can become unauthenticated remote code execution on the web server.
The vendor's CRITICAL 9.8 rating is mostly deserved in practice. The only meaningful downward pressure is population size: this is a third-party Magento extension, not Magento core, so reachability is narrower than the raw CVSS suggests. But that friction is overwhelmed by the ugly amplifiers: unauthenticated remote trigger, ordinary web traffic path, internet-facing storefront exposure, server-level compromise, and CISA KEV evidence as of 2026-06-03.
5 steps from start to impact.
Reach any storefront page with curl
GET / to an internet-facing Magento site is enough to reach the code path. Tooling here is trivial: curl, Burp, or any commodity botnet HTTP client.- Target runs Mirasvit Full Page Cache Warmer before 1.11.12
- Storefront is reachable over HTTP/HTTPS
- The vulnerable module is enabled in the Magento app
- Only merchants with this extension are exposed; this is not all Magento
- Some stores may sit behind a WAF/CDN that blocks malformed cookie payloads
Build a gadget payload with PHPGGC
PHPGGC or equivalent custom serialization code to generate a chain that turns deserialization into command execution. This is the standard weaponization pattern for CWE-502 in PHP ecosystems.- A compatible gadget chain exists in the target Magento/dependency set
- Attacker can encode the serialized object into the
CacheWarmercookie format
- Gadget reliability can vary across Magento builds and dependency versions
- Poorly chosen gadget chains may crash the request instead of yielding execution
CacheWarmer cookie values and follow-on PHP/webshell artifacts.Send the malicious CacheWarmer cookie
CacheWarmer cookie and sends it to any storefront endpoint. Sansec notes a strong request signature: CacheWarmer: followed by a base64 blob, with serialized-object prefixes commonly starting Tz, Qz, or YT. Tooling remains basic HTTP automation; no race, auth bypass, or user interaction is required.- Application accepts the request and passes the cookie to the vulnerable plugin
- The payload survives any CDN/WAF normalization
- Well-tuned WAF rules can block this exact cookie pattern
- Header size limits or proxy normalization may break oversized payloads
CacheWarmer:(Tz|Qz|YT) patterns as Sansec recommends.Trigger unserialize() and gain code execution
- The vulnerable deserialization path executes successfully
- The PHP runtime and file permissions allow useful post-execution actions
- Filesystem hardening can limit persistence options
- Containerized or read-only deployments may constrain payload choices
Persist and monetize with skimmers or webshells
pub/ or other web-reachable directories, modify templates or PHP, and monetize via card-skimming, credential theft, or redirect fraud. That aligns with the real-world blast radius of e-commerce compromises: customer data, admin sessions, and revenue flow all sit in scope.- Attacker obtains successful code execution
- No immediate containment removes dropped artifacts
- File integrity monitoring and Magento malware scanners can catch common persistence
- Fast rebuild/redeploy pipelines reduce dwell time
pub/ and other web-accessible directories for unexpected PHP files. That is the right hunt path.The supporting signals.
| In-the-wild status | Yes. NVD shows this CVE is in CISA KEV; the KEV entry was added on 2026-06-03 for "Mirasvit Full Page Cache Warmer Deserialization of Untrusted Data Vulnerability." |
|---|---|
| KEV dates | Added to KEV: 2026-06-03. NVD reflects CISA due date metadata and marks the CVE as KEV-listed. |
| Proof-of-concept availability | No authoritative public GitHub exploit repo surfaced in the sources I reviewed, but weaponization is straightforward: curl/Burp for delivery plus PHPGGC-style gadget generation. Low public-PoC visibility does not reduce operational risk here. |
| EPSS | 0.00137 from the supplied intel, which is low. That is a classic case where EPSS lags on fresh, ecosystem-specific flaws and should lose to KEV + active exploitation evidence. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — the vector says internet-reachable, no auth, no user action, full CIA impact. That technical framing matches reality unusually well. |
| Affected versions | All versions before 1.11.12. Sansec also notes the module is bundled with several Mirasvit packages, so some merchants may have it installed indirectly. |
| Fixed version | Vendor fixed it in 1.11.12 on 2026-05-25. Mirasvit changelog states: "Fixed PHP Object Injection vulnerability in session cookie deserialization." No distro backport path is relevant for this commercial Magento extension. |
| Exposure and scanning data | Sansec says its scans found roughly 6,000 stores running Mirasvit extensions, and the real number is likely higher because CDNs like Cloudflare hide many installs. That is not internet-scale like Apache, but it is plenty large for criminal targeting. |
| Disclosure timeline | Sansec discovered the flaw on 2026-04-24, notified Mirasvit on 2026-05-21, vendor patched on 2026-05-25, and public disclosure/CVE assignment landed on 2026-05-26. |
| Researcher and detection clue | Reported by Sansec Forensics Team. Their detection note is strong: suspicious CacheWarmer cookies matching CacheWarmer:(Tz|Qz|YT) are a high-signal exploitation indicator. |
noisgate verdict.
The decisive factor is attacker position: this is an unauthenticated remote bug reachable over ordinary storefront traffic, not a post-auth or internal-only edge case. The extension-only population narrows exposure somewhat, but KEV listing on 2026-06-03 and direct server-compromise impact wipe out most of that downward pressure.
Why this verdict
- No-auth internet path: the attacker starts from ordinary web access to the storefront; there is no requirement for prior compromise, credentials, or user interaction.
- Extension-only scope is the main friction: this is not Magento core, so the exposed population is narrower than the raw 9.8 suggests; that trims the score slightly but not the severity bucket.
- KEV overrides comfort metrics: the supplied EPSS is low, but KEV status and public exploitation evidence are stronger signals than a fresh-model probability estimate.
- Blast radius is server-level, not feature-level: once exploited, the attacker owns the PHP app context and can plant skimmers, webshells, or credential theft logic across the storefront.
Why not higher?
It is not higher than 9.4 because the reachability depends on a specific third-party extension being present and enabled. That is real population friction compared with a core Magento flaw or a ubiquitous server component, so I would shave the score a bit even while keeping the CRITICAL bucket.
Why not lower?
A lower rating would ignore the key reality that this is unauthenticated RCE over the public storefront with KEV evidence. There is no internal-network, post-auth, or special-role prerequisite to push this down into HIGH; the only real brake is install base, and that is not enough.
What to do — in priority order.
- Block the
CacheWarmercookie at the edge — Deploy a WAF/CDN rule within hours that denies or strips suspiciousCacheWarmercookies, especially values matching Sansec'sCacheWarmer:(Tz|Qz|YT)pattern. This buys time only for stores that cannot patch immediately; because this is KEV-listed, treat edge blocking as emergency containment, not closure. - Disable the module if business can tolerate it — If cache warming is non-essential, disable
mirasvit/module-cache-warmeror remove the extension within hours on exposed storefronts. That removes the vulnerable code path entirely and is the cleanest compensating control short of patching. - Hunt for dropped PHP in web-reachable paths — Review
pub/, media-adjacent writable locations, and any custom upload directories today for unexpected PHP files, altered templates, or skimmer logic. This matters because successful RCE on Magento commonly turns into webshell or checkout-skimmer persistence very quickly. - Search logs for exploit signatures — Query reverse-proxy, CDN, and web-server logs today for requests carrying the
CacheWarmercookie, especially serialized-object prefixes and unusual base64 blobs. This is one of the rare RCEs with a pretty solid request-layer hunting indicator. - Tighten Linux app telemetry on these hosts — If you cannot patch immediately, enable or tune EDR/FIM for web-root writes, new PHP files, cron changes, and outbound connections from the PHP worker within hours. That will not prevent exploitation, but it improves your odds of catching the monetization phase.
- Relying on Magento admin MFA or admin IP restrictions does not help; the bug is hit from the public storefront, not the admin panel.
- Assuming latest Magento core is enough does not help if the vulnerable Mirasvit extension is still present; this is an extension flaw with gadget-chain leverage from the broader PHP app.
- Generic network segmentation does little for initial exploitation because the vulnerable surface is the internet-facing web tier itself.
Crowdsourced verification payload.
Run this on the target Magento host from the Magento application root, for example: sudo bash ./check-cve-2026-45247.sh /var/www/html/magento. It needs read access to composer.lock, composer.json, and optionally vendor/mirasvit/module-cache-warmer/etc/module.xml; root is not required if the Magento files are readable.
#!/usr/bin/env bash
# check-cve-2026-45247.sh
# Detects whether a Magento instance is vulnerable to CVE-2026-45247
# by checking installed version of mirasvit/module-cache-warmer.
#
# Usage:
# bash check-cve-2026-45247.sh /path/to/magento
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
set -u
TARGET_DIR="${1:-.}"
PACKAGE="mirasvit/module-cache-warmer"
FIXED="1.11.12"
if [ ! -d "$TARGET_DIR" ]; then
echo "UNKNOWN: target directory not found: $TARGET_DIR"
exit 2
fi
LOCK_FILE="$TARGET_DIR/composer.lock"
JSON_FILE="$TARGET_DIR/composer.json"
MODULE_XML="$TARGET_DIR/vendor/mirasvit/module-cache-warmer/etc/module.xml"
version_lt() {
# returns 0 (true) if $1 < $2
[ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" != "$2" ]
}
extract_from_lock() {
local file="$1"
python3 - "$file" "$PACKAGE" <<'PY'
import json, sys
path, package = sys.argv[1], sys.argv[2]
try:
with open(path, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception:
sys.exit(1)
for section in ('packages', 'packages-dev'):
for pkg in data.get(section, []) or []:
if pkg.get('name') == package:
ver = pkg.get('version', '')
print(ver.lstrip('v'))
sys.exit(0)
sys.exit(1)
PY
}
extract_from_composer_json() {
local file="$1"
python3 - "$file" "$PACKAGE" <<'PY'
import json, sys
path, package = sys.argv[1], sys.argv[2]
try:
with open(path, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception:
sys.exit(1)
for section in ('require', 'require-dev'):
reqs = data.get(section, {}) or {}
if package in reqs:
print(str(reqs[package]).strip())
sys.exit(0)
sys.exit(1)
PY
}
VERSION=""
SOURCE=""
if [ -f "$LOCK_FILE" ] && command -v python3 >/dev/null 2>&1; then
VERSION="$(extract_from_lock "$LOCK_FILE" 2>/dev/null)"
if [ -n "$VERSION" ]; then
SOURCE="composer.lock"
fi
fi
if [ -z "$VERSION" ] && [ -f "$JSON_FILE" ] && command -v python3 >/dev/null 2>&1; then
VERSION="$(extract_from_composer_json "$JSON_FILE" 2>/dev/null)"
if [ -n "$VERSION" ]; then
SOURCE="composer.json"
fi
fi
if [ -z "$VERSION" ] && [ -f "$MODULE_XML" ]; then
# Module exists but version may not be recoverable reliably from filesystem alone.
echo "UNKNOWN: module files present but version not reliably determined; check composer metadata manually"
exit 2
fi
if [ -z "$VERSION" ]; then
echo "PATCHED: package $PACKAGE not found in composer metadata"
exit 0
fi
# Normalize common Composer constraints / prefixes when extracted from composer.json.
NORM="$VERSION"
NORM="${NORM#v}"
NORM="${NORM#~}"
NORM="${NORM#^}"
NORM="${NORM#>=}"
NORM="${NORM#=}"
NORM="${NORM%% *}"
NORM="${NORM%%,*}"
case "$NORM" in
''|dev-*|*@*|*x-dev*|*@dev*|*'||*' )
echo "UNKNOWN: found non-concrete version '$VERSION' in $SOURCE"
exit 2
;;
esac
if version_lt "$NORM" "$FIXED"; then
echo "VULNERABLE: $PACKAGE version $VERSION detected via $SOURCE; fixed version is $FIXED"
exit 1
else
echo "PATCHED: $PACKAGE version $VERSION detected via $SOURCE; fixed version is $FIXED"
exit 0
fiIf you remember one thing.
CacheWarmer cookie at the edge today if you cannot patch immediately, and hunt for webshell/skimmer artifacts today. The formal noisgate remediation SLA for a CRITICAL issue is ≤90 days, but for this one that window is only your outer exception boundary; any exposed production storefront still on <1.11.12 after the first business day is an avoidable risk.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.