A back-door pass into the storeroom that only reads the packing slips, not the products
The Avada (Fusion) Builder plugin's fusion_get_post_custom_field() helper accepts a post_custom_field parameter from the Dynamic Data feature and returns the requested meta value without checking whether the key begins with an underscore. In WordPress, an underscore prefix is the canonical marker for *protected* post meta — used by ecommerce plugins, license managers, and custom workflows to store internal state like SKUs, payment tokens, hidden order data, or plugin scratch fields. All versions ≤ 3.15.1 are affected; the vendor shipped the fix in 3.15.2, which validates the requested key against is_protected_meta() before returning the value.
The vendor MEDIUM (4.3) label is honest. The CVSS vector AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N correctly captures a network-reachable, authenticated, confidentiality-only leak with no integrity or availability impact. If anything, in a hardened WordPress install where open Subscriber registration is disabled, the real-world reachable population is smaller than the vector implies — pushing this into LOW territory for most enterprise footprints. It is not a system-compromise bug; it is a reconnaissance primitive.
4 steps from start to impact.
Obtain a Subscriber-level account on the target site
Anyone can register in WP General Settings), this is a one-click account. On enterprise sites with registration disabled and SSO-gated logins, this step alone eliminates the vulnerability.- Target site runs WordPress with the Avada theme and Fusion Builder ≤ 3.15.1
- Attacker can create or acquire a Subscriber (or higher) account
- Most B2B / marketing sites disable public registration
- Sites behind SSO / VPN / IP allowlist are not reachable to arbitrary attackers
Enumerate post IDs with dynamic-data-bearing content
/wp-json/wp/v2/posts, and archive pages. Tools: wpscan --enumerate p, feroxbuster, or a curl loop against /?p=<id>. This step has zero friction and no detection signal on a typical site.- Site exposes the standard REST API or public post archives
- None meaningful — WP defaults expose post enumeration
Invoke Fusion Builder Dynamic Data with an underscore-prefixed key
fusion_get_post_custom_field() with post_custom_field=_wc_order_key, _billing_email, _edd_payment_meta, _license_key, or any other guessed protected meta key. Because the function skips the is_protected_meta() check, the value is returned in the rendered fragment. PoC scripts have been published against the post_custom_field parameter shape.- Valid nonce/cookie from the authenticated Subscriber session
- Target post carries the guessed protected meta key
- Attacker must guess or dictionary-attack meta key names — no listing primitive
- Sites that don't run WooCommerce / EDD / LMS have little sensitive
_metato leak
fusion_get_post_custom_field calls after the April 2026 rule push.Chain leaked data into follow-on abuse
- Sensitive PII / tokens actually stored in protected meta
- Downstream systems that trust those secrets
- Modern WooCommerce stores tokenize payment data via gateways (Stripe, Braintree) — raw card data is not in post meta
- GDPR/PCI-aware operators minimize what lives in
_meta
post_custom_field values starting with _. Apply within your normal WAF rule-update cadence — no mitigation SLA at LOW, but it costs nothing if you already run one of these WAFs.wp db query "SELECT DISTINCT meta_key FROM wp_postmeta WHERE meta_key LIKE '\_%'" and identify keys carrying PII, license keys, or tokens. Where feasible, move secrets out of post meta into a dedicated encrypted store. This is defense-in-depth beyond CVE-2026-1541.is_protected_meta() guard). Target the noisgate remediation SLA of ≤ 365 days for LOW verdicts.- MFA on WordPress logins — the attacker only needs a valid Subscriber session, which they can create legitimately via self-registration; MFA on their own attacker-owned account does not protect the site.
- Removing the Fusion Builder Dynamic Data UI from admin views — the vulnerable code path is invoked server-side via the AJAX/preview endpoint, not gated by the admin UI being visible.
- Network-layer segmentation of the WP host — the vuln is
AV:Nand reached through the normal public HTTPS front door; internal segmentation does not change reachability.
The supporting signals.
| In-the-wild status | No confirmed exploitation. Not tracked in CISA KEV. No campaigns reported by Wordfence, Sucuri, or Patchstack as of July 2026. |
|---|---|
| Proof-of-concept | Public technical writeups on wp-firewall.com and managed-wp.com. Trivial curl-based PoC — a shell one-liner reproduces it. |
| EPSS | 0.00269 (~19th percentile) — low exploitation likelihood over the next 30 days. |
| KEV status | Not listed on CISA KEV as of 2026-07-15. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N — network, low complexity, low priv required, confidentiality-only, no integrity/availability. |
| Affected versions | Avada (Fusion) Builder ≤ 3.15.1 (all prior releases). |
| Fixed version | 3.15.2 — adds is_protected_meta() guard on the post_custom_field parameter. No distro backports (commercial theme distributed via ThemeForest / ThemeFusion updater). |
| Exposure population | Avada is bundled with the Avada theme (>950k ThemeForest sales lifetime). Publicscanning via WPScan API shows a long tail of unpatched sites, but the *authenticated + registration-enabled* subset is a fraction of that. |
| Disclosure | Published 2026-04-15 (NVD) / 2026-04-22 (GHSA-j7wx-2ff4-pc88). |
| Reporter | Coordinated via Wordfence vulnerability research program. |
Sources.
Why this verdict
- Authenticated precondition compresses reachable population — Subscriber capability is required; enterprise-hosted Avada sites overwhelmingly disable public registration or gate it behind CAPTCHA + email verification, cutting the attacker-accessible population dramatically.
- Confidentiality-only, bounded blast radius — the vector is
C:L / I:N / A:N. No write, no code execution, no session forgery. Worst plausible outcome is exposure of order emails, license keys, or plugin scratch fields — a privacy incident on a single site, not fleet compromise. - Role multiplier: low-value role (marketing/CMS tier) — Avada is a *frontend page-builder theme*. Its canonical deployment is marketing/brochure sites, WooCommerce storefronts, and campaign microsites — not an identity provider, hypervisor, PAM, CI/CD, or backup plane. The chain does NOT reach domain/fleet/supply-chain scale in any realistic deployment role, so no HIGH/CRITICAL floor is triggered.
- Role multiplier: typical role (WooCommerce storefront) — the worst-case data leak is customer email / order metadata. Impact is a GDPR-reportable privacy incident scoped to one site's customer list, not multi-tenant compromise. Still bounded within LOW/MEDIUM.
- No wormable, no auth-bypass, no chain to admin — the bug cannot be pivoted into WP admin without a separate privilege-escalation vulnerability. EPSS 0.00269 and no KEV listing corroborate the low weaponization interest.
Why not higher?
MEDIUM would be defensible if Avada sites broadly enabled open registration or if the leak included credentials/tokens usable against WP admin — neither generalizes. The bug cannot write, escalate, or execute; upgrading to HIGH would ignore the confidentiality-only vector and the absence of any exploitation signal.
Why not lower?
IGNORE is wrong because a real information-disclosure primitive exists with a public PoC, and WooCommerce-backed Avada storefronts genuinely store customer PII in post meta. It deserves scheduled patching, not silent acceptance.
Crowdsourced verification payload.
Run this from an auditor workstation with curl and jq installed. It probes the Fusion Builder plugin readme for its declared version — no auth required, no exploit sent. Invoke as ./check-cve-2026-1541.sh https://target-site.example.com. No elevated privileges needed.
#!/usr/bin/env bash
# check-cve-2026-1541.sh — Avada Fusion Builder version check for CVE-2026-1541
# Exit: 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN
set -u
if [ $# -lt 1 ]; then
echo "usage: $0 <https://target-site>" >&2
exit 2
fi
TARGET="${1%/}"
FIXED="3.15.2"
UA="noisgate-cve-2026-1541-check/1.0"
# Candidate readme locations shipped by Fusion Builder
PATHS=(
"/wp-content/plugins/fusion-builder/readme.txt"
"/wp-content/plugins/fusion-builder/fusion-builder.php"
)
version=""
for p in "${PATHS[@]}"; do
body=$(curl -sk -A "$UA" --max-time 10 "${TARGET}${p}" || true)
# readme.txt: 'Stable tag: 3.15.1' plugin header: 'Version: 3.15.1'
v=$(printf '%s\n' "$body" | grep -Ei '^(Stable tag|Version)[[:space:]]*:' | head -1 | awk -F: '{print $2}' | tr -d ' \r')
if [ -n "$v" ]; then version="$v"; break; fi
done
if [ -z "$version" ]; then
echo "UNKNOWN — Fusion Builder readme not reachable at ${TARGET}"
exit 2
fi
# semver-ish compare
lower=$(printf '%s\n%s\n' "$version" "$FIXED" | sort -V | head -1)
if [ "$version" = "$FIXED" ] || [ "$lower" = "$FIXED" ]; then
echo "PATCHED — Fusion Builder ${version} (>= ${FIXED})"
exit 0
else
echo "VULNERABLE — Fusion Builder ${version} (< ${FIXED}) — CVE-2026-1541"
exit 1
fi