This is a front-desk badge printer that will issue a master key if any paying guest presses the right button
CVE-2026-6898 is a missing capability check in WishListMember3_Hooks::generate_api_key in WishList Member for WordPress. Affected versions are all releases up to and including 3.30.1; the fix is reported by Patchstack as 3.31.0. The vulnerable path lets an authenticated low-privilege user hit the wlm3_generate_api_key AJAX action, replace the plugin's REST API secret, and then use that new secret to create an administrator-capable membership level and an arbitrary admin user.
The vendor-style 8.8 HIGH score gets the *impact* right but overstates the *reach*. This is not unauthenticated remote code execution against every public WordPress site; it needs a valid account first and a commercial plugin with a relatively small exposed footprint. But because this is a membership plugin, the Subscriber prerequisite is materially weaker than it sounds in many real deployments, so this stays HIGH instead of dropping to medium.
4 steps from start to impact.
Land a Subscriber account
admin-ajax.php. On WishList Member deployments, that often means self-registration, cheap trial access, reused credentials, or a previously compromised customer account rather than a full initial breach. Tooling is pedestrian: Burp Suite, curl, or credential-stuffing kits are enough.- WishList Member is installed and vulnerable (
<= 3.30.1) - Attacker has valid WordPress credentials at Subscriber level or above
- The site exposes a member login or registration path
- No unauthenticated path
- Closed-membership sites with manual approval block the easiest route
- MFA or anti-automation on login raises cost
Call wlm3_generate_api_key
/wp-admin/admin-ajax.php, the attacker invokes the vulnerable AJAX action that ultimately reaches WishListMember3_Hooks::generate_api_key. Because the function lacks a capability check, the application treats a Subscriber like an administrator for this operation. The weaponized tools here are simple HTTP clients, not exploit frameworks.- Authenticated session or valid cookies/nonces if required by the action wiring
- Endpoint reachable at
/wp-admin/admin-ajax.php
- A WAF or custom rule targeting the specific AJAX action can stop this cold
- Some sites may layer extra access control around admin AJAX
- Nonce handling can slow blind automation even if it does not fix the bug
action=wlm3_generate_api_key. Native WordPress logs usually do not give enough semantic detail unless request logging is already enabled.Rotate the REST API secret
- The AJAX action successfully updates or exposes the API secret
- WishList Member REST API functionality is enabled as normal
- If API access is disabled or heavily filtered, the chain may stop here
- Operators who rotate the secret quickly can invalidate attacker follow-on requests
Create an admin-mapped level and user
- Attacker can reach the WishList Member API endpoints
- API operations permit level creation and user registration
- No secondary control blocks role assignment changes
- Change monitoring on roles, plugins, or newly created admins can contain blast radius
- Some hardened sites disable plugin/theme editing from the dashboard
administrator, and plugin/theme installs shortly after member-logins.The supporting signals.
| In-the-wild status | No CISA KEV listing found, and I found no primary-source public exploitation bulletin for this exact CVE. |
|---|---|
| Proof-of-concept availability | I found no exact public PoC for CVE-2026-6898; however, the exploit path is low-complexity and Patchstack/NVD describe the vulnerable AJAX action clearly enough that reproduction is straightforward. |
| EPSS | 0.00044 from the user-provided intel block, which is very low and consistent with a niche product plus authenticated-only reach. |
| KEV status | Not listed in the CISA Known Exploited Vulnerabilities Catalog. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — the crucial term is PR:L. On paper that is a major brake; on a membership plugin it is less comforting because low-privilege users are part of the product design. |
| Affected versions | Authoritative CVE/NVD text says all versions up to and including 3.30.1 are affected. |
| Fixed version | Patchstack reports 3.31.0 as the patched version. Vendor release notes for 3.31.0 list security fixes, though they do not name this CVE explicitly. |
| Exposure footprint | WebTechSurvey currently reports roughly 468 observed domains using WishList Member X, with 280 in the U.S. That is not tiny, but it is far from a mass-market WordPress plugin. |
| Disclosure timeline | NVD published the CVE on 2026-05-23; Patchstack published its advisory on 2026-05-25. |
| Researcher / source | NVD lists Wordfence as the source CNA. Patchstack credits researcher h0xilo on its advisory page. |
noisgate verdict.
The single most decisive factor is that this bug requires authenticated Subscriber access, which cuts out true internet-wide opportunistic exploitation. It still lands in HIGH because this is a membership plugin: on many affected sites, low-privilege member accounts are easy to obtain and the end state is full WordPress administrator takeover.
Why this verdict
- Downgrade from 8.8:
PR:Lmatters in the real world; the attacker needs a working account first, which is a meaningful prerequisite versus unauthenticated WordPress bugs. - Not a full downgrade to medium: this is a *membership* plugin, so Subscriber accounts are often normal business objects, not rare internal users. That weakens the usual comfort defenders take from
PR:L. - Blast radius is total on a hit: once the REST API secret is rotated, the attacker can create an admin-capable membership level and arbitrary admin users, which is effectively site takeover.
- Exposure is narrower than commodity WordPress bugs: observed public footprint is in the hundreds of domains, not hundreds of thousands, which caps campaign value and keeps the score below the vendor baseline.
- Threat intel is quiet: no KEV entry, no exact public PoC located, and a very low EPSS all argue against pushing this into the top emergency tier today.
Why not higher?
This is not unauthenticated and not broadly applicable across the WordPress ecosystem; it only matters where WishList Member is installed and vulnerable. I also found no hard evidence of active exploitation or an exact public PoC for this CVE, which removes the biggest reason to score it as near-critical.
Why not lower?
On affected membership sites, the authentication requirement is often weak in practice because obtaining or creating a low-tier member account may be cheap, automated, or entirely expected. And once the bug is reached, the chain does not stop at data tampering; it ends in administrator creation and durable control of the site.
What to do — in priority order.
- Block the AJAX action — Deploy a WAF or reverse-proxy rule that denies requests to
/wp-admin/admin-ajax.phpwhenaction=wlm3_generate_api_key. This is the cleanest temporary choke point and should be in place within 30 days if you cannot patch immediately. - Freeze low-trust registrations — Disable open signup, free trials, or automated member onboarding on vulnerable sites until patched if the business can tolerate it. This attacks the most important prerequisite — a Subscriber account — and should be applied within 30 days where patching lags.
- Alert on admin creation and role-map drift — Add detections for new
administratorusers, membership-level changes mapped to admin, and API key regeneration events. This will not prevent exploitation, but it gives you the best chance of catching follow-on abuse within 30 days while patch rollout finishes. - Constrain admin AJAX where possible — If member workflows do not require broad admin AJAX access, put path-based filtering or authenticated application proxy rules in front of
/wp-admin/admin-ajax.php. Apply within 30 days on internet-facing membership sites that cannot be patched quickly. - Cull stale subscribers — Remove dormant member accounts, especially trial, coupon, and abandoned-payment users. Reducing the pool of low-privilege accounts lowers the exploitable population and should be completed within 30 days for exposed sites.
- Relying on nonce checks alone does not solve a missing capability check; a valid low-privilege session can still be unauthorized for the action.
- Generic EDR on the web server will not stop the initial privilege escalation because the exploit is an application-layer logic bug, not malware execution at first touch.
- Blocking
/wp-admin/broadly does not necessarily help if legitimate member workflows already exposeadmin-ajax.php; many WordPress sites intentionally leave that path reachable.
Crowdsourced verification payload.
Run this on the target WordPress host or a mounted web root from an auditor workstation. Invoke it as bash check_wlm_cve_2026_6898.sh /var/www/html and use a user that can read the WordPress files; root is not required unless filesystem permissions are tight.
#!/usr/bin/env bash
# check_wlm_cve_2026_6898.sh
# Detects whether WishList Member for WordPress is vulnerable to CVE-2026-6898
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 1=vulnerable, 0=patched, 2=unknown
set -u
SAFE_VERSION="3.31.0"
WP_PATH="${1:-.}"
PLUGIN_SLUG="wishlist-member-x"
PLUGIN_DIR="$WP_PATH/wp-content/plugins/$PLUGIN_SLUG"
verlte() {
[ "$1" = "$2" ] && return 0
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ]
}
extract_version_from_file() {
local f="$1"
[ -f "$f" ] || return 1
awk -F': *' '/^[[:space:]]*Version:[[:space:]]*/ {print $2; exit}' "$f" | tr -d '\r'
}
find_version() {
local v=""
if command -v wp >/dev/null 2>&1; then
v=$(wp --path="$WP_PATH" plugin get "$PLUGIN_SLUG" --field=version 2>/dev/null | tr -d '\r')
if [ -n "$v" ]; then
printf '%s' "$v"
return 0
fi
fi
if [ ! -d "$PLUGIN_DIR" ]; then
return 1
fi
for candidate in \
"$PLUGIN_DIR/wishlist-member-x.php" \
"$PLUGIN_DIR/wishlist-member.php" \
"$PLUGIN_DIR/plugin.php" \
"$PLUGIN_DIR/wlm.php" \
"$PLUGIN_DIR/loader.php"
do
v=$(extract_version_from_file "$candidate")
if [ -n "$v" ]; then
printf '%s' "$v"
return 0
fi
done
v=$(grep -R -m1 -h -E '^[[:space:]]*Version:[[:space:]]*[0-9]+' "$PLUGIN_DIR" 2>/dev/null | head -n1 | sed -E 's/^[[:space:]]*Version:[[:space:]]*//; s/\r$//')
if [ -n "$v" ]; then
printf '%s' "$v"
return 0
fi
return 1
}
VERSION="$(find_version)"
STATUS=$?
if [ $STATUS -ne 0 ] || [ -z "$VERSION" ]; then
echo "UNKNOWN: Could not determine WishList Member version at $WP_PATH"
exit 2
fi
if verlte "$VERSION" "3.30.1"; then
echo "VULNERABLE: WishList Member version $VERSION is <= 3.30.1 (fixed in $SAFE_VERSION or later)"
exit 1
fi
if verlte "$SAFE_VERSION" "$VERSION"; then
echo "PATCHED: WishList Member version $VERSION is >= $SAFE_VERSION"
exit 0
fi
echo "UNKNOWN: Detected version $VERSION but could not classify confidently"
exit 2
If you remember one thing.
<= 3.30.1, prioritize the ones that allow self-registration or have large subscriber populations, and put an interim block on the wlm3_generate_api_key AJAX action where patching is not immediate. For a HIGH verdict, the noisgate mitigation SLA is within 30 days for compensating controls, and the noisgate remediation SLA is within 180 days for the actual upgrade to 3.31.0 or later; in practice, anything public-facing with open member onboarding should be treated faster than the bare SLA because the auth prerequisite is weaker than normal on this product.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.