This is a rotten screen door on a shed, not a blown vault door
CVE-2025-31431 is a reflected XSS bug in the WordPress wp-bookmarks plugin from conlabz GmbH, affecting all versions through 1.1. An unauthenticated attacker can craft a malicious request that reflects attacker-controlled input into a page; the payload only fires if a victim user loads the crafted URL or otherwise performs the required action in a browser session.
The vendor/CNA CVSS 7.1 HIGH is technically defensible from a pure CVSS standpoint, but it overstates enterprise urgency. The real-world chain has two big brakes: user interaction is mandatory and the plugin is tiny/removed/unpatched, with Wordfence showing only about 60 active installs and WordPress.org showing the plugin was closed on March 24, 2025 for a security issue. That makes this a cleanup-and-replace issue, not an all-hands patch fire.
4 steps from start to impact.
Find a site still running wp-bookmarks
httpx, wpscan, or custom search dorks can help, but this is not the same as scanning for a clean RCE banner.- Target runs WordPress with the
wp-bookmarksplugin installed - Attacker can reach the vulnerable web application over HTTP/HTTPS
- Plugin appears removed/closed from WordPress.org
- Very small estimated install base reduces reachable population
- No reliable network signature for broad internet-scale detection
Build the reflected XSS lure
Burp Suite, the attacker crafts a URL or request parameter that causes unsanitized input to be reflected into a response. This is straightforward technically, but only becomes useful if the target application exposes the vulnerable code path and reflects the payload in an executable browser context.- Vulnerable parameter/path is reachable
- Reflected payload lands in a browser-executable context
- The issue is reflected, not stored, so there is no durable foothold
- Payload effectiveness depends on exact page context and browser parsing
Social-engineer a victim into clicking
GoPhish or commodity phishing kits is enough here; the browser is the execution environment, not the server.- Victim user clicks the lure or visits a crafted page
- Victim has an active browser session against the target site or can reach it
- User interaction required is the decisive brake
- Modern email security, browser protections, and user awareness training disrupt this step
- If only low-privilege users click, business impact drops sharply
Abuse the victim browser session
BeEF or custom JavaScript can weaponize the session, but the impact is still bounded by the victim's privileges and browser/session controls.- Payload executes in the victim browser
- Victim has useful privileges in WordPress
- Impact is usually limited to the victim session rather than direct server-side code execution
- HttpOnly cookies, CSP, nonce validation, and re-auth flows reduce post-XSS leverage
- No evidence of active exploitation or KEV inclusion
The supporting signals.
| In-the-wild status | No confirmed active exploitation found in primary-source review; not in CISA KEV. |
|---|---|
| Proof-of-concept availability | No widely indexed public PoC located in primary-source search. This lowers urgency, but confidence is only LOW-to-MEDIUM because simple reflected XSS payloads are trivial to recreate. |
| EPSS | 0.00219 (~0.219%), consistent with a low near-term exploitation probability signal. |
| KEV / CISA enrichment | OpenCVE shows KEV: no and CISA ADP SSVC values of Exploitation: none, Automatable: no, Technical Impact: partial. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L — remote, unauthenticated, but click-required and only low CIA impact. |
| Affected versions | All versions through 1.1 are affected. |
| Fixed version | No official patched version published. Patchstack and Wordfence both mark it effectively unpatched; WordPress.org closed the plugin on 2025-03-24 for a security issue. |
| Exposure / prevalence | Wordfence lists the plugin as Removed, with roughly 3,297 downloads and 60 active installs. That is a very small exposed population compared with enterprise-priority WordPress plugin bugs. |
| Disclosure / reporting | Publicly disclosed 2025-04-01; researcher credited as johska via Patchstack. |
| Scanner coverage reality | Inventory-based detection is stronger than perimeter scanning here. Many enterprise scanners will miss abandoned niche plugins unless WordPress plugin enumeration or filesystem inspection is enabled. |
noisgate verdict.
The single most important brake is mandatory user interaction: this bug does nothing until someone loads a crafted link, which pushes it out of the emergency lane. The second decisive factor is tiny exposure—this is a removed, ancient plugin with a very small active install base, so the reachable population is narrow even before phishing friction is applied.
Why this verdict
- Start at 7.1 HIGH: the CNA scored it as unauthenticated remote reflected XSS, which is fair in CVSS terms.
- Downward adjustment for attacker position: exploitation is remote and unauthenticated, but it requires victim browser interaction. That implies a phishing or lure stage that modern email security, browser controls, and user behavior often stop.
- Downward adjustment for reachability: the product is a removed niche plugin with about 60 active installs reported by Wordfence, so the exposed population is tiny relative to mainstream enterprise web software.
- Downward adjustment for blast radius: this is session/context abuse, not direct server-side RCE. Impact depends heavily on who clicks and what their WordPress role can do.
- Downward adjustment for threat evidence: no KEV listing, EPSS is low, and no strong public exploitation signal was found.
Why not higher?
There is no evidence of active exploitation, no KEV listing, and no sign this is being weaponized at scale. More importantly, the chain still hinges on a victim click and then on the victim having useful WordPress privileges, which is materially weaker than a pre-auth server-side bug.
Why not lower?
It is still unauthenticated remote input reaching script execution in a browser, and if an administrator clicks, the attacker may pivot into meaningful site actions. The plugin is also unpatched/removed, so affected installs do not have a clean vendor-upgrade path and need direct operator action.
What to do — in priority order.
- Remove the plugin — If
wp-bookmarksexists anywhere, remove it and replace the functionality with a maintained alternative. Because this verdict is MEDIUM, there is no mitigation SLA — go straight to the 365-day remediation window; in practice, abandoned plugins should be eliminated far sooner during normal hygiene work. - Block risky plugin paths at the edge — If immediate removal is delayed, add temporary WAF or reverse-proxy rules for any known
wp-bookmarksroutes and suspicious reflected-input patterns. This is a stopgap only; for MEDIUM there is no mitigation SLA, but the control reduces opportunistic drive-by exploitation until the plugin is removed. - Hunt by filesystem and inventory — Search fleets for
/wp-content/plugins/wp-bookmarks/and correlate with external site ownership so you can identify the handful of real exposures fast. This is the highest-ROI move for a 10,000-host estate because internet scanning will not reliably find every abandoned plugin. - Protect admin sessions — Enforce MFA on WordPress admin accounts, limit administrator count, and prefer re-auth for sensitive actions where possible. These controls do not fix XSS, but they reduce the value of a compromised browser session while you clean out the plugin.
- Blindly trusting network vulnerability scans — they often miss niche or removed WordPress plugins unless plugin enumeration or host inspection is enabled.
- MFA alone — helpful for account takeover risk, but it does not prevent malicious JavaScript from acting inside an already-authenticated browser session.
- Relying on a future vendor patch — there is no official fixed version published, and the plugin has already been closed from WordPress.org.
Crowdsourced verification payload.
Run this on the target WordPress host or on a mounted backup of the webroot. Invoke it as bash check-wp-bookmarks-cve-2025-31431.sh /var/www/html with read access to the WordPress files; root is not required unless your webroot permissions are restrictive.
#!/usr/bin/env bash
# check-wp-bookmarks-cve-2025-31431.sh
# Purpose: Detect whether WordPress plugin wp-bookmarks is installed and vulnerable to CVE-2025-31431.
# Usage: bash check-wp-bookmarks-cve-2025-31431.sh /path/to/wordpress
# Exit codes:
# 0 = PATCHED (plugin absent or version > 1.1)
# 1 = VULNERABLE (plugin present and version <= 1.1)
# 2 = UNKNOWN (cannot determine)
set -u
WP_ROOT="${1:-}"
if [[ -z "$WP_ROOT" ]]; then
echo "UNKNOWN: missing WordPress root path argument"
exit 2
fi
PLUGIN_DIR="$WP_ROOT/wp-content/plugins/wp-bookmarks"
MAIN_FILE=""
VERSION=""
if [[ ! -d "$PLUGIN_DIR" ]]; then
echo "PATCHED: wp-bookmarks plugin not present at $PLUGIN_DIR"
exit 0
fi
# Try likely main plugin files first.
for f in "$PLUGIN_DIR/wp-bookmarks.php" "$PLUGIN_DIR/index.php"; do
if [[ -f "$f" ]]; then
MAIN_FILE="$f"
break
fi
done
# Fallback: search first-level PHP files for a plugin header or version string.
if [[ -z "$MAIN_FILE" ]]; then
while IFS= read -r -d '' f; do
if grep -qiE '^[[:space:]]*Version:[[:space:]]*[0-9]' "$f"; then
MAIN_FILE="$f"
break
fi
done < <(find "$PLUGIN_DIR" -maxdepth 1 -type f -name '*.php' -print0 2>/dev/null)
fi
# Try readme.txt first, then plugin main file.
if [[ -f "$PLUGIN_DIR/readme.txt" ]]; then
VERSION=$(grep -iE '^(Stable tag|Version):' "$PLUGIN_DIR/readme.txt" | head -n1 | sed -E 's/^[^:]+:[[:space:]]*//' | tr -d '\r')
fi
if [[ -z "$VERSION" && -n "$MAIN_FILE" && -f "$MAIN_FILE" ]]; then
VERSION=$(grep -iE '^[[:space:]]*Version:[[:space:]]*' "$MAIN_FILE" | head -n1 | sed -E 's/^[^:]+:[[:space:]]*//' | tr -d '\r')
fi
if [[ -z "$VERSION" ]]; then
echo "UNKNOWN: wp-bookmarks directory exists but version could not be determined"
exit 2
fi
# Normalize version string to first token.
VERSION=$(echo "$VERSION" | awk '{print $1}')
# Compare versions using sort -V.
lowest=$(printf '%s\n%s\n' "$VERSION" "1.1" | sort -V | head -n1)
if [[ "$lowest" == "$VERSION" && "$VERSION" != "1.1+" ]]; then
# VERSION <= 1.1
echo "VULNERABLE: wp-bookmarks version $VERSION detected at $PLUGIN_DIR"
exit 1
fi
echo "PATCHED: wp-bookmarks version $VERSION is greater than 1.1"
exit 0
If you remember one thing.
wp-bookmarks, remove or replace the plugin, and document any business exception. For a MEDIUM verdict there is noisgate mitigation SLA — no mitigation SLA — go straight to the 365-day remediation window — but because there is no vendor patch and the plugin was removed for a security issue, the practical move is to clean it out during the next normal web-platform maintenance cycle rather than let an abandoned plugin sit until the far edge of the noisgate remediation SLA.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.