Someone left the back door unlocked and propped open with a sign saying 'free webshells inside'
CVE-2026-85097 is an unauthenticated arbitrary file upload vulnerability in the Bricksforge plugin for WordPress (an addon for the Bricks visual page builder). The flaw lives in the Pro Forms module's temporaryFileUploads handling: Bricksforge validates a file's MIME type at initial upload but then blindly trusts the client-supplied url field during form submission. An attacker obtains a nonce from the unauthenticated bricksforge_regenerate_nonce AJAX endpoint, uploads a GIF/PHP polyglot that passes the MIME check, then submits a form where the temporaryFileUploads parameter pairs the validated image path with a .php destination URL. The server writes the polyglot's contents to the PHP path and Apache/Nginx executes the embedded code — full webshell, no credentials required. Affected: Bricksforge ≤ 3.1.8.9. Fixed: 3.1.8.10.
The vendor severity of CRITICAL 9.8 is dead-on — arguably conservative, since Patchstack scores it 10.0. Every prerequisite is attacker-supplied: the nonce endpoint requires no auth, the MIME check is trivially bypassed with a polyglot, and the file-write target is entirely client-controlled. There is zero friction in the chain. Patchstack observed exploitation before public disclosure (October 7, 21:47 UTC — the advisory dropped October 8), 63 unique source IPs are actively scanning, and a Python PoC from *RootMantap* hit GitHub on October 14. For any site running Bricksforge with Pro Forms active, this is a walk-in-the-front-door RCE.
4 steps from start to impact.
Nonce acquisition
wp-admin/admin-ajax.php?action=bricksforge_regenerate_nonce. The endpoint has no capability check — it returns a fresh, valid WordPress nonce to anyone who asks. This nonce is required for subsequent API calls but costs the attacker one HTTP request and zero credentials.- Target runs WordPress with Bricksforge ≤ 3.1.8.9 active
- The
bricksforge_regenerate_nonceAJAX action is registered (always is when plugin is active)
- None — endpoint is unconditionally available
bricksforge_regenerate_nonce. Patchstack vPatching blocks this.GIF/PHP polyglot upload
/wp-content/uploads/bricksforge/tmp/). The file is a valid GIF image whose trailing bytes contain <?php code. Because Bricksforge validates the MIME type at upload time and the file genuinely satisfies image/gif, it passes. Tools like *RootMantap/CVE-2026-85097* automate polyglot generation.- Valid nonce from step 1
- Bricksforge Pro Forms module is active on at least one page
- None — polyglot generation is trivial and well-documented
930120 rule family may flag polyglot content.Form submission with mismatched extension
/wp-json/bricksforge/v1/form_submit (or admin-ajax.php?action=bricksforge_form_submit) with a temporaryFileUploads array. The file field points to the uploaded GIF path; the url field ends in .php. Bricksforge does not validate or sanitize the url field — it uses it as the destination path and writes the polyglot contents there. Attackers rotate extensions (.php, .php5, .php7, .phtml, .pht) and use URL-encoding or case manipulation to evade naive blocklists.- Valid nonce
- Polyglot file present in tmp directory
- A WAF rule specifically matching image-path + PHP-destination pairs would block this, but no default WordPress WAF ships such a rule
form_submit endpoints with temporaryFileUploads containing .php in the url field. Patchstack RapidMitigate covers this.Webshell execution
.php file at its predictable URL under /wp-content/uploads/. The web server executes the PHP code, giving the attacker arbitrary command execution as the web server user (www-data / nginx / apache). From here, standard post-exploitation applies: database credential extraction from wp-config.php, lateral movement, crypto-mining, SEO spam injection, or pivot into internal networks if the web server has internal connectivity.- PHP execution is enabled in the uploads directory (default on nearly all WordPress hosts)
- Disabling PHP execution in uploads via
.htaccessor Nginx config blocks this step, but this is not a WordPress default
.php files under /wp-content/uploads/bricksforge/. EDR or HIDS alerts on www-data spawning shells.php_flag engine off to /wp-content/uploads/.htaccess (Apache) or location ~* /wp-content/uploads/.*\.php$ { deny all; } to your Nginx config. This breaks the final step of the chain — the polyglot is written but never executed. Deploy within 3 days per noisgate mitigation SLA for CRITICAL findings. This is the single most effective compensating control if you cannot patch immediately.admin-ajax.php with action=bricksforge_regenerate_nonce. Without a valid nonce, the subsequent form submission fails. Deploy within 3 days. Note: this may break legitimate Bricksforge form functionality for anonymous visitors — test in staging first.url field in temporaryFileUploads and rejects mismatched extensions. Current latest is 4.0.1. Apply within 90 days per noisgate remediation SLA, but given active exploitation, treat this as immediate — patch within hours if possible.- WordPress built-in file type checking (
DISALLOW_UNFILTERED_UPLOADS) — this constant only affects the media library uploader and admin-side uploads. Bricksforge's Pro Forms upload path is a custom AJAX/REST handler that does not honor this constant. - Generic upload size limits — the polyglot payload is tiny (a few hundred bytes appended to a valid GIF header). Size restrictions will not block it.
- Cloudflare 'Under Attack Mode' — this adds a JavaScript challenge for browsers but does not block server-to-server POST requests from automated exploit scripts that handle the challenge or target the REST API directly.
- Disabling XML-RPC — this vulnerability uses the REST API and admin-ajax.php, not XML-RPC. Disabling XML-RPC provides no protection.
The supporting signals.
| In-the-wild exploitation | Active. Patchstack observed exploitation beginning 2026-10-07 21:47 UTC — one day *before* public disclosure. 63 unique source IPs identified; 6 IPs account for ~46% of traffic. Infrastructure spans datacenters, cloud, VPN/proxy, and residential ISPs. (Patchstack, SecurityWeek) |
|---|---|
| Proof-of-concept | Public. Python PoC by RootMantap/CVE-2026-85097 published 2026-10-14, indexed on Sploitus. Additional PoC references in SecureWithUmer/CVE-2026-PoCs. Not yet indexed on pocindex.io. |
| EPSS | 0.00312 (31st percentile). Low EPSS reflects model lag — the CVE is only 6 days old and EPSS has not yet ingested the active-exploitation signal. Treat this score as stale. |
| KEV status | Not listed as of 2026-10-14. Given confirmed in-the-wild exploitation, KEV addition is probable in the near term. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — 9.8 (Wordfence). Patchstack scores 10.0. Network-accessible, no authentication, no user interaction, full CIA impact. The vector is accurate. |
| Affected versions | Bricksforge ≤ 3.1.8.9 (all versions with Pro Forms). Parent theme: Bricks Builder (premium, estimated 30,000–50,000 active sites based on addon install proxies). Bricksforge is a third-party premium addon — no WordPress.org listing, so exact install count is unavailable. |
| Fixed version | 3.1.8.10 (released ~2026-10-08). Current latest is 4.0.1 (2026-10-09). |
| Scanning / exposure | All affected sites are internet-facing WordPress installations by nature. Attackers are rotating PHP extensions (.php, .php5, .php7, .php8, .phtml, .pht, .phps) and using case manipulation / URL-encoding to evade WAF rules. 44 IPs sent identical payloads within seconds; 3 IPs tested 25+ extension variations. |
| Disclosure date | 2026-10-08 (Patchstack advisory). Pre-disclosure exploitation confirmed from 2026-10-07. |
| Reporting researcher | d.v4n_s3c (credited on CVE record). Patchstack performed the technical analysis and coordinated disclosure. |
Sources.
Why this verdict
- Zero-friction attack chain: Every prerequisite is attacker-supplied. The nonce endpoint is unauthenticated, the MIME check is bypassed with a trivial polyglot, and the destination path is entirely client-controlled. There is no step in this chain that requires credentials, user interaction, or special network position.
- Active pre-disclosure exploitation: Patchstack telemetry confirms exploitation beginning 2026-10-07, *before* the advisory. 63 source IPs are scanning. This is not theoretical — sites are being popped right now.
- Public weaponized PoC: RootMantap's Python exploit dropped the same day as this assessment (2026-10-14). The barrier to mass exploitation is a
pip install requestsaway. - Internet-facing by definition: WordPress sites run on the public internet. There is no 'internal-only deployment' friction to discount. Every Bricksforge installation with Pro Forms is reachable.
- Role multiplier: Bricksforge is a WordPress CMS plugin, not a canonical high-value-role component (not an IdP, hypervisor, DC, or PKI system). The blast radius per compromised site is host-level: webshell →
wp-config.phpdatabase credentials → site data (PII, payment data on e-commerce sites) → potential pivot to internal network if the web server has LAN connectivity. For WordPress hosting providers or agencies running multi-tenant WordPress, a single compromised host can cascade to dozens of client sites — pushing toward fleet-scale impact in that deployment model. The host-level blast radius does not override the CRITICAL floor set by the frictionless, actively-exploited, unauthenticated RCE chain. - Install base limiter (insufficient to downgrade): Bricksforge is a niche premium addon (estimated 30K–50K sites vs. Elementor's 10M). This limits the *population* at risk but does not reduce the *severity per affected host*. CVSS scores individual-host impact, and for affected sites the impact is total compromise.
Why not higher?
The vendor score of 9.8 is already near-maximum. Patchstack's 10.0 reflects the nonce endpoint removing the last authentication barrier. The difference is academic — both map to CRITICAL. There is no meaningful argument for scoring higher than 9.8 under the CVSS:3.1 vector provided.
Why not lower?
Downgrading would require friction in the attack chain, and there is none. The attacker needs no credentials, no user interaction, no special network position, and no insider knowledge. The nonce is freely dispensed, the polyglot is trivial, and the file-write path is client-controlled. Active in-the-wild exploitation and a public PoC eliminate any residual argument for 'theoretical only.' The small install base limits *exposure* but not *severity* — CVSS and this assessment rate per-host impact, not population size.
Crowdsourced verification payload.
Run this script on each WordPress host (or via SSH from your management server) as any user with read access to the WordPress installation directory. Usage: bash check_cve_2026_85097.sh /var/www/html (pass the WordPress root path as the first argument). No root privileges required.
#!/usr/bin/env bash
# CVE-2026-85097 Checker — Bricksforge Unauthenticated File Upload → RCE
# Usage: bash check_cve_2026_85097.sh /path/to/wordpress
# Exit codes: 0 = PATCHED/not affected, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
WP_ROOT="${1:-/var/www/html}"
PLUGIN_DIR="$WP_ROOT/wp-content/plugins/bricksforge"
MAIN_FILE="$PLUGIN_DIR/bricksforge.php"
# Check if Bricksforge is installed
if [ ! -d "$PLUGIN_DIR" ]; then
echo "PATCHED — Bricksforge plugin not found at $PLUGIN_DIR. Not affected."
exit 0
fi
if [ ! -f "$MAIN_FILE" ]; then
echo "UNKNOWN — Bricksforge directory exists but main file not found."
exit 2
fi
# Extract version from plugin header
VERSION=$(grep -i '^[[:space:]]*\*[[:space:]]*Version:' "$MAIN_FILE" | head -1 | sed 's/.*Version:[[:space:]]*//' | tr -d '[:space:]')
if [ -z "$VERSION" ]; then
echo "UNKNOWN — Could not extract Bricksforge version from $MAIN_FILE."
exit 2
fi
echo "Detected Bricksforge version: $VERSION"
# Version comparison: vulnerable if <= 3.1.8.9
# Use sort -V for natural version sorting
FIXED="3.1.8.10"
OLDEST=$(printf '%s\n%s' "$VERSION" "$FIXED" | sort -V | head -1)
if [ "$VERSION" = "$FIXED" ] || [ "$OLDEST" = "$FIXED" ]; then
echo "PATCHED — Bricksforge $VERSION >= $FIXED. CVE-2026-85097 is fixed."
exit 0
else
echo "VULNERABLE — Bricksforge $VERSION < $FIXED. CVE-2026-85097 applies."
# Additional check: look for signs of compromise
UPLOADS="$WP_ROOT/wp-content/uploads/bricksforge/tmp"
if [ -d "$UPLOADS" ]; then
PHP_COUNT=$(find "$UPLOADS" -name '*.php' -o -name '*.php5' -o -name '*.php7' -o -name '*.php8' -o -name '*.phtml' -o -name '*.pht' 2>/dev/null | wc -l)
if [ "$PHP_COUNT" -gt 0 ]; then
echo "WARNING — Found $PHP_COUNT PHP file(s) in $UPLOADS — possible exploitation artifact!"
find "$UPLOADS" -name '*.php*' -o -name '*.phtml' -o -name '*.pht' 2>/dev/null
fi
fi
exit 1
fi