← Back to Feed CACHED · 2026-10-02 10:02:53 · CACHE_KEY CVE-2026-11387
CVE-2026-11387 · CWE-287 · Disclosed 2026-07-01

SMS Alert ≤ 3.9.5 Unauthenticated Privilege Escalation via OTP-Bypass Password Reset

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

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.

"Trivial admin takeover of WooCommerce shops, but only ~3K installs and needs OTP-reset enabled."
02 · The Attack Path

5 steps from start to impact.

STEP 01

Identify a target running SMS Alert ≤ 3.9.5

The attacker fingerprints the target WordPress site for the SMS Alert plugin. The plugin registers distinctive front-end JavaScript (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.
Conditions required:
  • Target site runs WordPress with WooCommerce
  • SMS Alert plugin ≤ 3.9.5 is installed and activated
Where this breaks in practice:
  • 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
Detection/coverage: WPScan plugin detection, custom Nuclei template for /wp-json/smsalert/v1/ endpoint enumeration
STEP 02

Confirm OTP password-reset is enabled

The attacker sends a GET request to the WordPress lost-password page (/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.
Conditions required:
  • OTP verification for password resets must be enabled in plugin settings (non-default configuration)
Where this breaks in practice:
  • 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
STEP 03

Trigger session poisoning via lost-password POST

The attacker POSTs to the lost-password endpoint with the target username (e.g., 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.
Conditions required:
  • Attacker knows or guesses a valid WordPress username (default admin or enumerable via /?author=1 or REST API /wp-json/wp/v2/users)
  • Target user has a billing phone number stored in WooCommerce user meta
Where this breaks in practice:
  • 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
Detection/coverage: Wordfence login-attempt logging, Cloudflare WAF rate-limit alerts on /wp-login.php
STEP 04

Bypass OTP and reset password

With the session poisoned, the attacker immediately POSTs a second request with 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.
Conditions required:
  • Session from Step 3 must be maintained (same HTTP session / cookies)
Where this breaks in practice:
  • 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-form option value if a custom rule is deployed
Detection/coverage: PHP session anomaly logging; WAF custom rules matching option=smsalert-change-password-form in POST body
STEP 05

Log in as administrator — full site compromise

The attacker logs in with the new credentials. As WordPress administrator, they can install arbitrary plugins (webshells), modify theme files for persistent backdoors, exfiltrate WooCommerce customer data including PII and potentially stored payment tokens, and pivot to the underlying server if the hosting configuration permits code execution from plugin uploads.
Conditions required:
  • Successful password reset from Step 4
Where this breaks in practice:
  • 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
Detection/coverage: WordPress login audit logs, Wordfence live-traffic monitoring, host-based file-integrity monitoring for new plugin uploads
03 · Compensating Control

1
HIGH 8.1→IGNORE 0.0
SEVERITY REDUCED
Disable OTP-based password resets in SMS Alert settings immediately — Navigate to WP Admin → SMS Alert → Settings → Password Reset and disable the OTP password-reset feature. This removes the vulnerable code path entirely without uninstalling the plugin. Order notifications and login OTP continue to function. Deploy within the noisgate mitigation SLA of 30 days (HIGH verdict), though given the trivial exploitation, doing this within 48 hours is prudent.
2
HIGH 8.1→IGNORE 0.0
SEVERITY REDUCED
Update SMS Alert to version 4.0.0 or later — Version 3.9.6 patched CVE-2026-11387, but subsequent auth-bypass CVEs (CVE-2026-66424 in 3.9.7, CVE-2026-62106 in 3.9.9) indicate ongoing fragility in the plugin's authentication logic. Jump to 4.0.0 to cover all three. This is the definitive remediation. Deploy within the noisgate remediation SLA of 180 days for HIGH.
3
HIGH 8.1→LOW 3.1
SEVERITY REDUCED
Enforce WordPress admin 2FA via a separate plugin — Deploy a dedicated two-factor authentication plugin (Wordfence 2FA, WP 2FA, or Duo) for all administrator and shop-manager accounts. Even if an attacker resets the password via CVE-2026-11387, they cannot complete login without the second factor. This does NOT prevent the password reset itself but blocks the final step (account access).
4
HIGH 8.1→LOW 2.5
SEVERITY REDUCED
Restrict wp-admin and wp-login.php access by IP or VPN — Use server-level access controls (nginx 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.
What doesn't work
  • Web Application Firewalls (generic rulesets): Standard WAF rules from Cloudflare, Sucuri, or ModSecurity do not inspect for option=smsalert-change-password-form in 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.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo 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 AvailabilityTwo 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 Score0.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 StatusNot listed. No CISA KEV entry as of 2026-10-02. No federal agency mandate to patch.
CVSS VectorCVSS: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 VersionsSMS Alert ≤ 3.9.5 (all versions). Plugin slug: sms-alert. Vendor: Cozy Vision Technologies Pvt. Ltd.
Fixed Version3.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 Date2026-07-01 (NVD published). Patch available since 2026-06-27 (pre-disclosure patch window of 4 days).
ResearcherBeelze (1beelze on GitHub). Additional PoC tooling by abraxas.

Sources.

  1. NVD – CVE-2026-11387
  2. GitHub PoC – abraxas/CVE-2026-11387-WooCommerce-SMS-OTP
  3. GitHub PoC – 1beelze/CVE-2026-11387
  4. CVE Feed – CVE-2026-11387 Detail
  5. WordPress.org – SMS Alert Plugin
  6. OpenCVE – CVE-2026-11387
  7. FIRST EPSS API – CVE-2026-11387
  8. Dark Web Informer – CVE-2026-11387 Alert
05 · The Call

Final Verdict
↓ DOWNGRADED to HIGH (8.1/10)

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:H in 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_phone in 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.

06 · Verification

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.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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