Someone left the vault door keyed to a doorbell that never actually rings
CVE-2026-11387 is an unauthenticated privilege-escalation flaw in the SMS Alert – SMS & OTP for WooCommerce WordPress plugin, affecting all versions through 3.9.5. The plugin's password-reset handler (smsalert_form_handler.php) checks only that $_REQUEST['option'] equals smsalert-change-password-form — it never confirms the OTP challenge was completed. An unauthenticated caller can set a new password for any user who has a phone number on file, including the WordPress administrator, without possessing or intercepting the OTP. Two public PoC exploit scripts make this point-and-click. The fix landed in 3.9.6 on June 27, 2026.
The vendor-assigned CVSS 9.8 CRITICAL is technically defensible on the vector math — it *is* unauthenticated, network-reachable, low-complexity, and leads to full-privilege account takeover. But the rating ignores two real-world narrowing factors: (1) the plugin has only ~3,000 active installations worldwide, making it virtually absent from enterprise asset inventories, and (2) the flaw is only reachable when the site administrator has explicitly enabled OTP-based password resets *and* the target account has a stored phone number. These are common configurations *among plugin users* but the population of plugin users is minuscule. noisgate downgrades to HIGH 8.1 — the chain is lethal where it lands, but it almost never lands in an enterprise.
5 steps from start to impact.
Identify a target running SMS Alert ≤ 3.9.5
smsalert-public.js) and REST routes (/wp-json/smsalert/v1/) that are trivially identifiable via path probing or Wappalyzer-style fingerprinting. WPScan and Nuclei templates can automate detection.- Target site runs WordPress with WooCommerce
- SMS Alert plugin ≤ 3.9.5 is installed and activated
- Only ~3,000 active installs globally; the odds of hitting one in a targeted enterprise campaign are near zero
- Plugin must appear in the site's active plugin list — deactivated installations are not exploitable
/wp-json/smsalert/v1/ endpoint enumerationConfirm OTP password-reset is enabled
/wp-login.php?action=lostpassword). If SMS Alert's OTP-reset feature is active, the page renders an SMS Alert–branded phone-number field instead of (or in addition to) the standard email field. This confirms the vulnerable code path is live.- OTP verification for password resets must be enabled in plugin settings (non-default configuration)
- Not all installations enable the OTP password-reset feature; some use SMS Alert only for order notifications or login OTP, which do not trigger the vulnerable handler
Trigger session poisoning via lost-password POST
admin). The plugin's class-wpresetpassword.php immediately sets $_SESSION['user_login'] to the submitted username and dispatches an OTP to the user's phone — but the session variable is now seeded regardless of whether the OTP is ever validated. This is the critical state-corruption step.- Attacker knows or guesses a valid WordPress username (default
adminor enumerable via/?author=1or REST API/wp-json/wp/v2/users) - Target user has a billing phone number stored in WooCommerce user meta
- WordPress user enumeration is commonly blocked by security plugins like Wordfence, iThemes Security, or All In One WP Security
- WAF rules from Cloudflare or Sucuri may rate-limit lost-password POST submissions
/wp-login.phpBypass OTP and reset password
option=smsalert-change-password-form and a new password value. The handler in smsalert_form_handler.php checks only for the presence of that option string and reads the username from $_SESSION['user_login'] — it never verifies the OTP was validated. The password is overwritten unconditionally. Both public PoCs (abraxas/CVE-2026-11387-WooCommerce-SMS-OTP and 1beelze/CVE-2026-11387) automate this two-request sequence.- Session from Step 3 must be maintained (same HTTP session / cookies)
- SameSite cookie policies or aggressive session-timeout settings could break the chain, though most default WordPress setups do not enforce these
- Sucuri or Wordfence firewall rules inspecting POST parameters could flag the
smsalert-change-password-formoption value if a custom rule is deployed
option=smsalert-change-password-form in POST bodyLog in as administrator — full site compromise
- Successful password reset from Step 4
- Two-factor authentication on the WordPress admin login (via a separate 2FA plugin like Wordfence 2FA, WP 2FA, or Duo) would block login even with the reset password
- IP-restricted wp-admin access or VPN-only admin panels would prevent login from an external attacker IP
allow/deny, Apache .htaccess, or Cloudflare Access) to limit /wp-admin/ and /wp-login.php to known admin IP ranges or VPN egress. This blocks external attackers from both triggering the exploit chain and logging in with stolen credentials.- Web Application Firewalls (generic rulesets): Standard WAF rules from Cloudflare, Sucuri, or ModSecurity do not inspect for
option=smsalert-change-password-formin POST bodies by default. Without a custom rule, the exploit sails through. A WAF gives false confidence here. - WordPress core auto-updates: WordPress core updates do not update third-party plugins. Auto-update must be explicitly enabled per-plugin or managed via a plugin management tool.
- Disabling XML-RPC or REST API: The exploit uses standard WordPress form POST endpoints (
/wp-login.php), not XML-RPC or the REST API. Disabling those hardening targets has zero effect on this chain.
The supporting signals.
| In-the-Wild Exploitation | No evidence. Not listed in CISA KEV. No GreyNoise tags or Shodan honeypot observations as of October 2026. Dark Web Informer flagged the CVE on X/Twitter but reported awareness, not active campaigns. |
|---|---|
| Proof-of-Concept Availability | Two public PoC repos on GitHub: abraxas/CVE-2026-11387-WooCommerce-SMS-OTP (Python, automated two-request chain) and 1beelze/CVE-2026-11387 (Python, published by researcher Beelze). Both are weaponized — point-and-shoot with a target URL and username. |
| EPSS Score | 0.02208 (81.94th percentile) — moderately elevated; reflects the availability of public PoCs but tempered by the tiny installed base. Higher than ~82% of all CVEs, but well below the >90th-percentile threshold that typically correlates with mass exploitation. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-10-02. No federal agency mandate to patch. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — The vector implies zero prerequisites, but real-world exploitation requires OTP-reset enabled and a phone number on file. A more honest AC:H would yield ~7.5, which aligns better with real conditions. |
| Affected Versions | SMS Alert ≤ 3.9.5 (all versions). Plugin slug: sms-alert. Vendor: Cozy Vision Technologies Pvt. Ltd. |
| Fixed Version | 3.9.6 (released June 27, 2026). Current version as of October 2026 is 4.0.0. Note: subsequent CVEs (CVE-2026-66424 in 3.9.7, CVE-2026-62106 in 3.9.9) suggest the auth logic was fragile — update to 4.0.0 or later. |
| Installed Base | ~3,000 active installations per WordPress.org. This is a niche WooCommerce add-on, not a widely-deployed enterprise component. For context, WooCommerce itself has 5M+ installs. |
| Disclosure Date | 2026-07-01 (NVD published). Patch available since 2026-06-27 (pre-disclosure patch window of 4 days). |
| Researcher | Beelze (1beelze on GitHub). Additional PoC tooling by abraxas. |
Sources.
Why this verdict
- Configuration prerequisite narrows exploitable population: The flaw requires OTP-based password resets to be explicitly enabled in plugin settings — this is not the default configuration. Sites using SMS Alert solely for order notifications or login OTP are not affected. This equates roughly to
AC:Hin CVSS terms, which alone drops the technical score from 9.8 to ~7.5. - Phone-number prerequisite adds a second gate: The target account must have a stored
billing_phonein WooCommerce user meta. While common for shop managers, not all admin accounts have this populated — especially on sites where the admin role is separated from the shop-owner role. - Tiny installed base eliminates enterprise relevance for most readers: ~3,000 active installations globally. In a fleet of 10,000 hosts, the probability of running this plugin is near zero unless you operate WooCommerce storefronts. This is not a component found on domain controllers, CI/CD pipelines, or infrastructure tiers.
- Public PoCs push upward: Two weaponized Python scripts lower the attacker skill barrier to near zero. Any script kiddie can run
python3 exploit.py https://target admin. This is the primary reason the verdict stays HIGH rather than MEDIUM. - Role multiplier: (a) *Low-value role* — dev/staging WordPress instances: chain succeeds, blast radius is negligible (test data only). (b) *Typical role* — production WooCommerce shops for SMBs: chain succeeds, blast radius is host-level (customer PII, payment tokens, webshell installation). This is the realistic worst case and it is serious but bounded to a single site. (c) *High-value role* — this plugin does not canonically occupy any fleet-scale, identity-scale, or supply-chain-scale role. WordPress is not AD, not a hypervisor, not a CI/CD runner. WooCommerce shops are standalone web applications. No floor applies.
- No active exploitation or KEV listing — the 3-month window since disclosure with zero observed exploitation reinforces that attackers are not prioritizing this target, consistent with its negligible internet footprint.
Why not higher?
The vendor's CRITICAL (9.8) would be justified if the plugin were ubiquitous and the prerequisites were universally met. Neither is true. With ~3,000 installs and two configuration gates, the real-world population of exploitable targets is measured in hundreds, not millions. The blast radius is host-scoped (a single WordPress site), not domain- or fleet-scoped. No high-value-role floor applies because the affected component is a niche WooCommerce add-on, not infrastructure software.
Why not lower?
The chain is unauthenticated, trivially scripted, and leads to full administrator takeover with no user interaction. Two public PoCs exist. Where the prerequisites are met — and they commonly are among the plugin's own user base — exploitation is instant and devastating. Dropping below HIGH would understate the risk for the ~3,000 sites that actually run this plugin. EPSS at the 82nd percentile also indicates non-trivial exploitation likelihood.
Crowdsourced verification payload.
Run this script on the WordPress host (or any machine with wp-cli access to the target installation) as a user with read access to the WordPress directory. Usage: bash check_cve_2026_11387.sh /var/www/html (pass the WordPress root path as the first argument). No root required — just read access to plugin files.
#!/usr/bin/env bash
# check_cve_2026_11387.sh — Detect CVE-2026-11387 in SMS Alert plugin
# Usage: bash check_cve_2026_11387.sh /path/to/wordpress
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
set -euo pipefail
WP_ROOT="${1:-.}"
PLUGIN_DIR="$WP_ROOT/wp-content/plugins/sms-alert"
MAIN_FILE="$PLUGIN_DIR/sms-alert.php"
if [ ! -d "$PLUGIN_DIR" ]; then
echo "UNKNOWN — SMS Alert plugin not found at $PLUGIN_DIR"
exit 2
fi
if [ ! -f "$MAIN_FILE" ]; then
echo "UNKNOWN — Main plugin file not found at $MAIN_FILE"
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 parse version from $MAIN_FILE"
exit 2
fi
echo "Detected SMS Alert version: $VERSION"
# Compare versions: vulnerable if <= 3.9.5
# Using sort -V for version comparison
MIN_SAFE="3.9.6"
SORTED_FIRST=$(printf '%s\n%s' "$VERSION" "$MIN_SAFE" | sort -V | head -1)
if [ "$VERSION" = "$MIN_SAFE" ] || [ "$SORTED_FIRST" = "$MIN_SAFE" ]; then
echo "PATCHED — SMS Alert $VERSION >= $MIN_SAFE (CVE-2026-11387 fixed)"
# Additional check: recommend 4.0.0+ due to subsequent CVEs
SAFE_ALL="4.0.0"
SORTED_ALL=$(printf '%s\n%s' "$VERSION" "$SAFE_ALL" | sort -V | head -1)
if [ "$SORTED_ALL" = "$VERSION" ] && [ "$VERSION" != "$SAFE_ALL" ]; then
echo "WARNING — Version $VERSION is patched for CVE-2026-11387 but vulnerable to subsequent CVEs (CVE-2026-66424, CVE-2026-62106). Upgrade to 4.0.0+."
fi
exit 0
else
echo "VULNERABLE — SMS Alert $VERSION < $MIN_SAFE (CVE-2026-11387 applies)"
# Check if OTP password reset is enabled (optional deeper check)
HANDLER_FILE="$PLUGIN_DIR/handler/forms/smsalert_form_handler.php"
if [ -f "$HANDLER_FILE" ]; then
if grep -q 'smsalert-change-password-form' "$HANDLER_FILE" 2>/dev/null; then
echo " Vulnerable handler code confirmed in $HANDLER_FILE"
fi
fi
exit 1
fi