← Back to Feed CACHED · 2026-09-26 22:48:53 · CACHE_KEY CVE-2026-8293
CVE-2026-8293 · CWE-287 · Disclosed 2026-06-02

Really Simple Security WordPress Plugin 2FA OTP Bypass via Unprotected REST Endpoints

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

Your deadbolt only works if the burglar doesn't know the secret knock on the side door

CVE-2026-8293 is a two-factor authentication bypass in the Really Simple Security WordPress plugin (formerly Really Simple SSL) affecting all versions before 9.5.10.1. The plugin exposes two REST endpoints — /wp-json/really-simple-security/v1/two-fa/v2/do_not_ask_again and .../skip_onboarding — whose permission callbacks validate only the login_nonce (proof the password step succeeded) without checking whether the email OTP challenge was actually answered. An attacker who already holds valid credentials can POST that nonce to either endpoint and receive a fully authenticated WordPress session cookie, completely skipping the one-time-password step. Worse, the do_not_ask_again endpoint silently disables every 2FA provider on the victim account, ensuring persistence. The plugin has 3+ million active installations and the fixed version 9.5.10.1 shipped on April 29, 2026.

The vendor rates this HIGH / 7.5 with AC:H/PR:L, and that is broadly fair. The PR:L correctly captures the requirement for valid credentials — this is *not* an unauthenticated auth bypass like the earlier CVE-2024-10924 (CVSS 9.8). The AC:H accounts for the need to extract the login_nonce from the challenge-page response, though in practice the PoC shows this is trivially automatable with two sequential HTTP requests. The score might slightly overstate real-world risk given the very low EPSS (0.39%), no KEV listing, and no confirmed in-the-wild exploitation — but it correctly reflects the full C:H/I:H/A:H impact once the chain succeeds, since WordPress admin access routinely leads to RCE via plugin/theme file upload.

"2FA bypass requires stolen creds but then trivially grants admin with two curls"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Obtain valid WordPress credentials

The attacker needs a working username/password pair for a WordPress account with 2FA enabled. This could come from credential stuffing, phishing, a prior breach dump, or brute-forcing weak passwords. This is the highest-friction step in the chain and is a prerequisite the vulnerability itself does not provide.
Conditions required:
  • Valid username and password for the target WordPress site
  • Target account has email-based 2FA enabled via Really Simple Security
Where this breaks in practice:
  • Requires prior credential compromise — the vuln does NOT bypass password authentication
  • WordPress login pages can be protected by rate limiting, CAPTCHA, or IP allowlisting
  • Strong unique passwords eliminate this step entirely
Detection/coverage: Failed login attempts visible in WordPress auth logs and WAF logs; credential-stuffing patterns detectable by bot-management solutions.
STEP 02

Submit credentials and capture login_nonce

The attacker POSTs valid credentials to /wp-login.php. Because 2FA is enabled, WordPress returns a challenge page containing a login_nonce value rather than an authenticated session. The attacker parses this nonce from the HTML response. This is fully automatable — the PoC by John Umoru demonstrates it with a single curl command.
Conditions required:
  • Network access to the WordPress login endpoint
  • Plugin version < 9.5.10.1 installed and active
Where this breaks in practice:
  • WAF rules or geo-blocking may restrict access to wp-login.php
  • Some hosting providers block automated login attempts
Detection/coverage: Login attempt logged in WordPress; the 2FA challenge generation is logged by the plugin if logging is enabled.
STEP 03

POST nonce to vulnerable REST endpoint

The attacker sends a JSON POST to /wp-json/really-simple-security/v1/two-fa/v2/do_not_ask_again (or skip_onboarding) with the user_id and login_nonce. The endpoint's permission callback validates only the nonce — not whether OTP was answered — and calls wp_set_auth_cookie(), returning a fully authenticated session cookie. The do_not_ask_again variant also disables all 2FA providers on the account.
Conditions required:
  • Valid login_nonce from step 2 (time-limited)
  • REST API accessible (enabled by default in WordPress)
Where this breaks in practice:
  • Nonce has a time-to-live window, but the PoC handles this in a single automated flow
  • Disabling the REST API or restricting it via plugin/WAF would block this step
Detection/coverage: REST API access logged by web server; the endpoint path is distinctive and can be matched by WAF signature. No specific nuclei template confirmed as of September 2026.
STEP 04

Escalate to RCE via admin panel

With an admin session, the attacker can upload a malicious plugin or edit theme PHP files through the built-in editor, achieving remote code execution on the underlying web server. From there, lateral movement to databases, internal networks, or other hosted sites on shared infrastructure is possible.
Conditions required:
  • Compromised account must have administrator role
  • File editing or plugin upload not disabled via DISALLOW_FILE_EDIT / DISALLOW_FILE_MODS
Where this breaks in practice:
  • Hardened WordPress installations disable file editing in wp-config.php
  • Managed hosting platforms often restrict filesystem writes from the admin panel
  • EDR or file-integrity monitoring on the web server would flag new PHP files
Detection/coverage: File-integrity monitoring (e.g., OSSEC, Wazaa, Wordfence) detects new/modified PHP files; plugin installation events logged in WordPress audit trail.
03 · Compensating Control

1
HIGH 7.2→IGNORE 0.0
SEVERITY REDUCED
Update Really Simple Security to 9.5.10.1 or later immediately — The definitive fix. Version 9.5.10.1 adds has_configured_provider() validation that returns HTTP 403 before wp_set_auth_cookie() if an active 2FA provider exists. Current version is 9.8.3. WordPress auto-updates may have already applied this for sites with auto-updates enabled. Per the noisgate mitigation SLA for HIGH, deploy within 30 days; per the noisgate remediation SLA, complete across all instances within 180 days.
2
HIGH 7.2→LOW 3.0
SEVERITY REDUCED
Block vulnerable REST endpoints at WAF or reverse proxy — Add a WAF rule to deny POST requests matching /wp-json/really-simple-security/v1/two-fa/v2/do_not_ask_again and .../skip_onboarding. This directly breaks step 3 of the attack chain. Apply within 30 days per noisgate mitigation SLA for HIGH if patching is delayed.
3
HIGH 7.2→LOW 2.5
SEVERITY REDUCED
Restrict wp-login.php to trusted IPs or VPN — Limit access to the WordPress login page via IP allowlist, VPN requirement, or Cloudflare Access / zero-trust proxy. This breaks step 2 by preventing the attacker from submitting credentials and obtaining the login_nonce. Deploy within 30 days per noisgate mitigation SLA.
4
HIGH 7.2→MEDIUM 5.5
SEVERITY REDUCED
Set DISALLOW_FILE_EDIT and DISALLOW_FILE_MODS in wp-config.php — Adding define('DISALLOW_FILE_EDIT', true); and define('DISALLOW_FILE_MODS', true); to wp-config.php prevents admin-panel RCE via theme/plugin editing. This does not prevent the 2FA bypass itself but eliminates the most dangerous post-exploitation escalation path (step 4). Deploy within 30 days.
5
HIGH 7.2→IGNORE 0.0
SEVERITY REDUCED
Switch to a TOTP-based 2FA plugin as a secondary control — If you cannot patch immediately, consider temporarily disabling Really Simple Security's 2FA and enabling a separate TOTP-based 2FA plugin (e.g., WP 2FA, Two-Factor). This eliminates the vulnerable code path entirely while maintaining 2FA protection. Deploy within 30 days per noisgate mitigation SLA.
What doesn't work
  • Disabling 2FA in Really Simple Security — While this technically removes the vulnerable endpoints from being exploitable (the nonce is only generated when 2FA is active), it also removes your second authentication factor entirely, leaving accounts with only password protection. This trades one risk for a worse one.
  • WordPress application-level rate limiting alone — Rate limiting on wp-login.php slows credential brute-forcing but does not prevent exploitation when the attacker already has valid credentials from a prior breach. The 2FA bypass itself is a single-request exploit after login.
  • Changing the WordPress admin username — Security-through-obscurity for the username does not help because the attacker already needs valid credentials (including the username) as a prerequisite for this vulnerability.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild StatusNo confirmed exploitation. Not listed in CISA KEV. No GreyNoise tags or Shadowserver reports observed as of September 2026. The prerequisite of valid credentials makes opportunistic mass exploitation unlikely.
Proof of ConceptPublic and weaponized. John Umoru published a full Python exploit and manual curl walkthrough at github.com/johnumorujo/published-cves. The PoC automates credential submission, nonce extraction, and 2FA bypass in a single script. No nuclei template confirmed yet; not indexed on pocindex.io as of this assessment.
EPSS0.00394 (~96th percentile). Very low exploitation probability, consistent with the credential prerequisite reducing mass-exploitation viability.
KEV StatusNot listed. No CISA KEV entry. No BOD 22-01 deadline applies.
CVSS VectorCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H — Network-accessible, high complexity (nonce extraction), low privileges required (valid creds), no user interaction. Full CIA impact on the WordPress instance. The AC:H is debatable given the trivial automation shown in the PoC.
Affected VersionsReally Simple Security (free, Pro, and Pro Multisite) all versions < 9.5.10.1. The 2FA feature was introduced in version 9.0 (September 2024 rebrand). Versions before 9.0 are not affected because they lack 2FA entirely.
Fixed Version9.5.10.1 (released April 29, 2026). Current latest is 9.8.3 (September 15, 2026). The vendor changelog described the fix as *"Updated 2FA login flow to address inconsistent verification behavior"* — a deliberately vague silent patch.
Install Base & Exposure3+ million active WordPress installations. WordPress sites are overwhelmingly internet-facing. However, exploitation requires valid credentials, not just network reachability, which sharply limits the attackable surface.
Disclosure TimelineCVE reserved May 11, 2026. WPScan publication May 12, 2026. NVD/MITRE publication June 2, 2026. Patch shipped April 29, 2026 — fix preceded public disclosure by ~2 weeks.
ResearcherJohn Umoru (finder). Coordinated through WPScan (coordinator). Full writeup and PoC on GitHub.

Sources.

  1. WPScan Advisory — CVE-2026-8293
  2. John Umoru PoC — RSSSL 2FA Bypass
  3. THREATINT CVE Detail
  4. Really Simple Security Vendor Advisory
  5. WordPress.org Plugin Page
  6. CyberStrike CVE Detail
  7. OpenCVE — CVE-2026-8293
05 · The Call

Final Verdict
= UNCHANGED to HIGH (7.2/10)

Why this verdict

  • Credential prerequisite is real friction: The attack chain begins with the attacker already possessing valid credentials. This is not an unauthenticated bypass (contrast CVE-2024-10924 at CVSS 9.8). The vulnerability degrades 2FA to single-factor auth — serious, but the hardest step (credential theft) is outside the vuln's scope.
  • Public PoC lowers the skill bar: John Umoru's GitHub repo provides a turnkey Python exploit. Once credentials are in hand, exploitation is two HTTP requests. This eliminates any complexity friction for motivated attackers and keeps the score in HIGH territory.
  • 3M+ installs but low exploitation probability: The large install base means many potentially vulnerable sites, but EPSS at 0.00394 and zero KEV/GreyNoise/exploitation signals after 5 months of disclosure indicate this is not being weaponized at scale. The credential prerequisite makes spray-and-pray impractical.
  • Role multiplier: WordPress is typically deployed as a *web content platform* — not in identity, hypervisor, CI/CD, or domain-controller roles. Blast radius is site-level (content manipulation, defacement, potential RCE on the web server) and host-level at worst. It does not meet the high-value-role floor for CRITICAL. In enterprise environments managing 10,000 hosts, WordPress instances are a small fraction of the fleet (typically single-digit servers), and admin compromise does not cascade to domain or fleet-level impact.
  • Silent patch shipped early: The fix landed April 29, 2026 — two weeks before WPScan disclosure. Organizations on auto-update (WordPress default for minor plugin releases) may already be patched. Current version is 9.8.3, four major releases ahead of the fix.

Why not higher?

This is not CRITICAL because the vulnerability requires valid credentials as a prerequisite — it is a 2FA bypass, not an authentication bypass. The blast radius is confined to the individual WordPress site and its underlying host, not fleet-scale or identity-scale. WordPress is not a canonically high-value-role component in enterprise architecture. There is no evidence of active exploitation, no KEV listing, and EPSS is very low. The earlier CVE-2024-10924 in the same plugin *was* CRITICAL (9.8) precisely because it required no credentials.

Why not lower?

Despite the credential prerequisite, this remains HIGH because credentials are routinely compromised via phishing, breaches, and stuffing — 2FA exists precisely to mitigate that scenario. A public, trivially weaponizable PoC is available. The do_not_ask_again endpoint silently disables all 2FA providers, granting persistence. WordPress admin access commonly leads to RCE via file upload. With 3M+ installations, even a small percentage of vulnerable sites represents tens of thousands of targets.

06 · Verification

Crowdsourced verification payload.

Run this script on the WordPress host with read access to the wp-content/plugins directory. Invoke as: bash check_cve_2026_8293.sh /var/www/html (pass the WordPress root path as the first argument). No elevated privileges required beyond filesystem read access to the plugin directory.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-8293 Checker - Really Simple Security 2FA Bypass
# Checks whether the installed plugin version is vulnerable.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -uo pipefail

WP_ROOT="${1:-/var/www/html}"
PLUGIN_DIR="$WP_ROOT/wp-content/plugins/really-simple-ssl"
FIXED="9.5.10.1"

if [ ! -d "$PLUGIN_DIR" ]; then
  echo "UNKNOWN - Really Simple Security plugin not found at $PLUGIN_DIR"
  exit 2
fi

# Extract version from main plugin header
VER=$(grep -iP '^\s*\*?\s*Version:\s*' "$PLUGIN_DIR/really-simple-ssl.php" 2>/dev/null \
  | head -1 | sed 's/.*[Vv]ersion:[[:space:]]*//' | tr -d '[:space:]')

# Fallback to readme.txt stable tag
if [ -z "$VER" ]; then
  VER=$(grep -iP '^Stable tag:' "$PLUGIN_DIR/readme.txt" 2>/dev/null \
    | head -1 | sed 's/.*[Tt]ag:[[:space:]]*//' | tr -d '[:space:]')
fi

if [ -z "$VER" ]; then
  echo "UNKNOWN - Could not determine plugin version"
  exit 2
fi

# Compare versions using sort -V
lowest=$(printf '%s\n%s\n' "$VER" "$FIXED" | sort -V | head -1)

echo "Detected version: $VER"
echo "Fixed version:    $FIXED"

if [ "$VER" = "$FIXED" ] || [ "$lowest" = "$FIXED" ]; then
  echo "PATCHED - Version $VER >= $FIXED"
  exit 0
else
  echo "VULNERABLE - Version $VER < $FIXED (CVE-2026-8293)"
  exit 1
fi