miniOrange SAML SSO CVE-2026-15981: Anyone Can Be Your WordPress Admin
CVE-2026-15981 (CVSS 9.8) and CVE-2026-61979 let an unauthenticated attacker forge a SAML assertion and log into wp-admin as anyone. Already probed in the wild. Here is the fix runbook.
Single sign-on exists to make one identity provider the single arbiter of who you are. When the code that checks the IdP's signature is wrong, that arbiter says yes to everyone. That is the situation the miniOrange SAML 2.0 Single Sign-On plugin for WordPress is in this week. Two vulnerabilities — CVE-2026-15981 (CVSS 9.8) and CVE-2026-61979 (CVSS 8.1, rated 9.8 by discoverer Patchstack) — let an unauthenticated attacker forge a SAML assertion the plugin accepts as genuine and walk into /wp-admin as any existing user, administrators included. Patchstack found the plugin publishing this door across seven separately versioned editions, and DigitalOcean has already caught someone knocking on it.
Two bugs, one door: how the miniOrange SAML SSO bypass works
A SAML login is a signed XML document. The identity provider asserts "this is Alice," signs the assertion with its private key, and the service provider — here, the WordPress plugin — verifies that signature against the IdP's public certificate before trusting the name inside. The security of the whole flow rests on one thing: the verifier must check the signature the way the IdP made it, over the bytes it actually consumes. The miniOrange plugin gets this wrong in two independent ways.
CVE-2026-61979 — algorithm confusion. The plugin lets the incoming SAML response pick its own signature algorithm instead of enforcing the one configured for the IdP. An attacker sets the algorithm to HMAC-SHA1. HMAC is a symmetric construction: signing and verifying use the same secret. The plugin, handed an HMAC-signed document, reaches for the only key material it has for that IdP — the RSA public certificate — and uses it as the HMAC secret. But that certificate is public. Anyone can download it. So the attacker computes a perfectly valid HMAC-SHA1 signature over an assertion of their choosing, using the same public key the plugin will verify with, and the check passes.
CVE-2026-15981 — the -1 that meant yes. The plugin's RSA verification path calls PHP's openssl_verify(), which returns three values, not two: 1 for a valid signature, 0 for an invalid one, and -1 for an error. The code treated the result as a boolean. In PHP, -1 is truthy. A malformed signature that makes OpenSSL error out returns -1, the plugin reads that as "valid," and the forged assertion sails through.
Either bug alone is game over. Together they mean neither the "use a symmetric key" path nor the "break the RSA math" path is closed.
An attacker doesn't need your IdP, your credentials, or a phishing lure. They fetch your public SAML certificate — it's public by design — craft an assertion that says
NameID: [email protected], sign it with an algorithm the plugin should have rejected, and POST it to your SSO endpoint. The plugin verifies the forgery against the very key that made it, finds no user by that name is required to prove anything, and hands back an authenticated admin session. Total interaction: one HTTP request.
Why SAML signature bugs keep coming back — a class, not an accident
If this feels familiar, it should. Zero Hunt's own knowledge base flags CVE-2026-61979 as a near-exact repeat of a bug that has been rediscovered in SAML library after SAML library. The pattern is always one of two shapes: verify a different algorithm than the IdP intended, or verify a different part of the document than you consume. The lineage is long and recent:
| Vulnerability | Library | Root cause |
|---|---|---|
| CVE-2024-45409 | Ruby-SAML | Signature verified on the wrong node; any IdP-signed doc could be reused to forge a response |
| GHSA-c27r-x354-4m68 | xml-crypto | HMAC-SHA1 key confusion — a valid signature forged from knowledge of the RSA public key alone |
| CVE-2017-11428 / -11429 | Ruby-SAML / saml2-js | XML canonicalization + DOM traversal mismatch (signature wrapping) |
| CVE-2021-21239 | PySAML2 | Improper signature verification in the default crypto backend |
| CVE-2025-54419 | Node-SAML | Assertion loaded from the unsigned original response, not the verified subset |
miniOrange CVE-2026-61979 is the xml-crypto key-confusion bug, re-implemented in PHP. CVE-2026-15981 is a variant of "the verifier returned something you didn't check carefully." None of these are exotic. They are what happens when SAML — a 20-year-old XML security standard with more optional features than most teams read — is implemented from scratch rather than delegated to a hardened, well-audited toolkit that enforces the algorithm and signs-what-it-reads by construction.
Seven editions, one slug: the patch-gap problem
The plugin ships under one WordPress slug, miniorange-saml-20-single-sign-on, but as seven independently versioned editions. The fixed versions are not "upgrade to 5.4.5" for everyone — each edition has its own line:
| Edition | Vulnerable up to | Fixed in |
|---|---|---|
| Free | 5.4.4 | 5.4.5 |
| Premium (single site) | 13.0.3 | 13.0.4 |
| Standard (single site) | 17.0.5 | 17.0.6 |
| Premium/Enterprise/All-Inclusive (multisite) | 20.2.7 | 20.2.8 |
| Enterprise/All-Inclusive (single site) | 26.0.2 | 26.0.3 |
| VIP (single site) | 32.0.7 | 32.0.8 |
| VIP (multisite) | 35.0.6 | 35.0.7 |
The dangerous part is not the version sprawl — it is the disclosure asymmetry. Per BleepingComputer, the vulnerabilities were fixed in July, but the vendor alerted only free-edition users. Paying customers on the Standard, Premium, Enterprise, and VIP tiers — the ones most likely to gate real business behind SSO — got a silent patch with no advisory. miniOrange reports roughly 30,000 customers across all editions; the free version alone shows about 10,000 active installs. A patch nobody is told to apply is, for exposure purposes, no patch at all.
In the wild already: what DigitalOcean saw
This is not theoretical. On August 16, 2026, DigitalOcean's security team detected — and blocked — an anomalous WordPress administrator session originating from outside their trusted network, and traced it to an exploitation attempt against the Standard edition. Patchstack documented the follow-on activity: opportunistic scanning from six IP addresses spread across Belgium, Nigeria, the United States, and Germany. SecurityWeek and The Hacker News both characterize the traffic as broad and opportunistic rather than a targeted campaign — which is worse, not better. Opportunistic means indiscriminate, and a public proof-of-concept for the free edition is already circulating. Every internet-reachable install running a vulnerable version is a candidate.
Remediation
Treat any site that had a vulnerable version internet-reachable after mid-July as possibly already accessed, not merely exposed. A forged-assertion login leaves a valid session, not a crash — the absence of errors is not the absence of compromise.
1. Am I affected? Confirm the plugin and its exact edition/version:
# From the WordPress root
wp plugin get miniorange-saml-20-single-sign-on --field=version
# Or without WP-CLI:
grep -i "Version:" wp-content/plugins/miniorange-saml-20-single-sign-on/*.php
Cross-reference the number against the edition matrix above. If you cannot immediately tell which edition you licensed, assume vulnerable until proven otherwise.
2. Patch — exact fixed versions. Update to the fixed build for your edition (Free ≥ 5.4.5, Standard ≥ 17.0.6, Premium ≥ 13.0.4, multisite Premium/Enterprise ≥ 20.2.8, Enterprise single ≥ 26.0.3, VIP single ≥ 32.0.8, VIP multisite ≥ 35.0.7). Because paid tiers were patched silently, do not wait for a vendor email — pull the update directly.
3. Can't patch now? — compensating controls.
- Put the SSO Assertion Consumer Service (ACS) endpoint behind a WAF rule that rejects SAML responses whose
SignatureMethodalgorithm is not the exact one your IdP uses (blockhmac-sha1outright — a real RSA-signed IdP never sends it). - IP-allowlist
/wp-adminand the ACS endpoint to your corporate egress ranges. DigitalOcean caught this precisely because the admin session came from an untrusted network. - If SSO is not actively in use, deactivate the plugin entirely rather than leaving a dormant, exploitable ACS endpoint listening.
4. Hunt for compromise. The forged login is Forge Web Credentials: SAML Tokens (MITRE ATT&CK T1606.002), typically followed by Valid Accounts (T1078) and, for persistence, Create Account (T1136) or a plugin/theme web shell (T1505.003). Look for:
- Successful admin logins via the SSO/ACS path from IP addresses outside your normal IdP or corporate ranges — the same signal DigitalOcean alerted on.
- SAML responses in web logs carrying an
HMAC-SHA1signature algorithm. - New
administrator-role users, application passwords, or REST API keys created shortly after an anomalous SSO login. - Recently modified or newly added files under
wp-content/(plugins,mu-plugins, uploads) — the classic post-auth web shell drop:
find wp-content -type f -name '*.php' -newermt '2026-07-01' \
-exec grep -lE 'eval\(|base64_decode\(|assert\(|system\(|passthru\(' {} \;
5. Eradicate + verify. If you find any indicator: patch first, then remove rogue admin accounts and any dropped web shells, rotate all administrator passwords, revoke application passwords and API keys, and force-invalidate active sessions (change WordPress auth salts in wp-config.php). Only after the plugin is on a fixed version does credential rotation stick — rotating before patching just hands the new session back through the same open door.
Where continuous validation would have closed this first
The uncomfortable fact about this bug is that it is invisible to everything that trusts the login. Once the plugin says "valid," the forged session is indistinguishable from a real one — no failed-auth spike, no malware signature, no crash. You do not find it by watching the front door; you find it by testing whether the front door can be forced before an attacker does.
That is the operational question Zero Hunt's 10-agent generative pentest is built to answer. Against an SSO surface, the Web and Credential agents don't fingerprint a version and match it to a CVE list — they generate a per-target exploit attempt: fetch the public certificate, craft an assertion with a downgraded signature algorithm, submit it, and report whether an authenticated admin session actually came back. That is a proven finding, ECDSA-signed at write time, not a "you appear to run a vulnerable version" guess. Because campaigns are change-triggered, the moment a new SSO endpoint appears on the perimeter — or a plugin update lands — the swarm re-validates it within the hour, backtested first in the AI Gym so the technique is known-good before it touches your environment.
Two things close the loop. The AI Traffic Analysis model catches the case where validation ran too late: its inference heads flag the anomalous admin session arriving from a never-seen ASN — the exact behavioural signal DigitalOcean acted on — while it is happening, not in the next morning's log review. And every finding maps automatically across the 32 compliance frameworks, so "we proved our SSO could not be forged, on this date, signed" becomes audit evidence for NIS2 and ISO 27001 access-control requirements instead of a screenshot in a slide deck. A patch you were never told to apply is only a risk until something independent of the vendor's mailing list goes looking. That is the job.