miniOrange SAML SSO flaw let attackers bypass WordPress admin
Two critical WordPress authentication bypass flaws in the miniOrange SAML 2.0 Single Sign On plugin, tracked as CVE-2026-61979 and CVE-2026-15981, allowed an unauthenticated attacker to sign in to a WordPress site as any existing user, including an administrator. Unauthenticated means the attacker needed no account and no password of their own. The discovery and the root cause analysis belong to the DigitalOcean security team, with coverage and vendor follow-up handled jointly with Patchstack. Both bugs carry a CVSS score of 9.8, a severity rating that runs from 0 to 10, and both were publicly disclosed in July 2026.
The plugin handles SAML, which stands for Security Assertion Markup Language, a standard that lets a website accept a login confirmed by an outside identity service instead of checking the password itself. That outside service is called the Identity Provider, or IdP. The two flaws both defeat that trust: they convince the plugin that a forged login message, called a SAML assertion, is genuine.
The first bug, CVE-2026-61979, is signature algorithm confusion. A signature is the digital stamp that proves a message really came from the trusted identity service. The plugin lets the incoming SAML response choose which signing method was used. An attacker can set that method to HMAC-SHA1, a way of signing with a shared secret string, and the plugin then accepts the identity provider's public RSA key as if it were that secret. A public key is, by design, public. So the attacker fetches the key from the identity provider's published metadata endpoint, signs their own assertion with it, and the plugin accepts the result as genuine. DigitalOcean's analysis of Standard edition 16.1.9 points to specific code paths: Utilities.php lines 246 to 250, which read the attacker-chosen algorithm and recast the RSA key; Utilities.php lines 259 to 281, which extract and reload the public key; and three spots in includes/lib/SAML2Core/XMLSecurityKey.php (lines 216 to 218, 308 to 314 and 546 to 548) that allow HMAC-SHA1 as an option, leave the public key material as raw bytes instead of rejecting it, and pass it straight into the hash_hmac function as the secret. miniOrange fixed this one in version 17.0.5 for the Standard edition.
The second bug, CVE-2026-15981, is a different mistake with the same outcome. The OpenSSL library function openssl_verify returns three possible answers: 1 for a valid signature, 0 for an invalid one, and -1 when OpenSSL itself hits an internal error. The plugin checked that result as a simple true or false, and in PHP the programming language WordPress runs on, the number -1 counts as true. So a malformed signature that trips OpenSSL's error path is treated as a valid signature. The code paths in version 16.1.9 are XMLSecurityKey.php lines 486 to 494, which returns the raw three-way result, and Utilities.php line 252, which turns it into a boolean. miniOrange fixed this in version 17.0.6 for the Standard edition. A third, separate issue was disclosed shortly after these fixes. It requires an administrator to click something (described in CVSS terms as UI:R), so it sits well below the other two in practical severity, but Patchstack notes it is worth patching in the same pass.
The reason this story is bigger than the code is the packaging. miniOrange ships all of these products under a single WordPress listing and slug, miniorange-saml-20-single-sign-on, and that one listing contains seven separately versioned editions. No two share a version number. The free single site edition runs from 3.0.0 and is currently at 5.4.7, and it was vulnerable up to and including 5.4.4, fixed in 5.4.5. Premium single site runs from 11.3.0 to 13.1.0, vulnerable up to 13.0.3 and fixed in 13.0.4. Standard single site runs from 15.1.0 to 17.1.0, vulnerable up to 17.0.5 and fixed in 17.0.6. The multisite Premium, Enterprise and All-Inclusive plan runs from 20.0.0 to 20.2.8, vulnerable up to 20.2.7 and fixed in 20.2.8. Enterprise and All-Inclusive single site runs from 25.0.0 to 26.1.0, vulnerable up to 26.0.2 and fixed in 26.0.3. VIP single site runs from 32.0.0 to 32.0.8, vulnerable up to 32.0.7 and fixed in 32.0.8. VIP multisite runs from 35.0.0 to 35.0.7, vulnerable up to 35.0.6 and fixed in 35.0.7. Because each edition spans several major version numbers, a version number on its own does not tell you which edition you are running. The vendor supplied this full breakdown to Patchstack, which says it had not been published anywhere before.
The public advisories for both CVEs covered only the free edition, the only one anyone can download from WordPress.org. That record said the plugin was affected up to and including 5.4.4 and fixed in 5.4.5. The record itself is correct, but it is a single range attached to a single slug. Every paid install carries a higher version number than 5.4.5, so every paid install read as already patched. A site on the vulnerable Standard release 16.1.9 was reported as unaffected, and so was every other vulnerable paid version in the 13.x, 20.x, 26.x, 32.x and 35.x lines. Widening the range does not fix it either: stretch the record to 17.0.5 so a vulnerable 16.1.9 is caught, and free-edition sites already patched on 5.4.5 or later start reporting as vulnerable instead. The vendor's table describes the affected set exactly as seven separate ranges on one slug, which is what the database record carries now. The six paid editions were patched with no public changelog entry and no public security advisory, which is how the whole downstream chain, databases, scanners and dashboards, went blind at once.
Remediation was just as hard to come by. Patchstack says WordPress sites on a vulnerable 16.x Standard release see no available update in the admin dashboard at all, even though the fixed 17.0.6 exists on the same Standard line the customer already holds a licence for. The typical WordPress update mechanism does not offer that kind of jump between major version lines, so the fix has to be uploaded manually.
What makes the case notable is how the problem was actually caught. There was no advisory to read and no database entry flagging the paid editions, and the plugin reported itself as fully up to date. Every signal that normally warns of trouble said everything was fine. DigitalOcean spotted it through defence in depth rather than through plugin data: an anomalous WordPress administrator session attempt arrived from outside its trusted network and was blocked. The attacker had already used the bypass to obtain an administrator session cookie, the token that keeps you logged in, but was stopped because admin panel operations on that infrastructure were restricted to the trusted network. The team then reproduced the bypass end to end on version 16.1.9, traced both bugs to specific lines, worked out which paid versions were affected where the vendor had published nothing, wrote and validated two hotfixes, and shared the analysis for publication.