SAML Single Sign On
Authentication Bypass
Reported by the DigitalOcean security team, with root cause analysis by DigitalOcean, coverage and vendor follow-up handled jointly with Patchstack.
Most vulnerability write-ups are about the bug. This is primarily about everything around the bug, where the actual risk ended up living.
The DigitalOcean security team identified a critical gap the hard way, based on their defense-in-depth controls. The version-level analysis that follows, which no public vulnerability database had, came out of DigitalOcean’s work.
Two critical authentication bypasses (CVSS 9.8) were publicly disclosed in July 2026 for the miniOrange SAML 2.0 Single Sign On plugin. Both allow an unauthenticated attacker to forge a SAML assertion and land in /wp-admin as any existing user, including administrators.
Both of these critical vulnerabilities were fixed. Yet a large group of sites and many enterprise customers running the plugin had no way of knowing they could be affected, did not see any pending update in their WordPress dashboard, and were not covered by any vulnerability database.
Here is what happened, why the coverage gap existed, and what to do if you are using this plugin on your WordPress website.
TL;DR:
- Two critical unauthenticated authentication bypasses in the miniOrange SAML 2.0 Single Sign On plugin, CVE-2026-61979 and CVE-2026-15981, made it possible for an attacker to sign in as any WordPress user, including administrators.
- The plugin ships under one single WordPress listing/slug, but that single listing quietly contains seven separate product plans with different versioning. The public security advisories only ever covered the free edition.
- The six paid editions were patched with no public changelog and no advisory, so no vulnerability database listed them, and vulnerable sites were incorrectly reported as unaffected.
- A vulnerable 16.x release has no managed update prompt at all. You’re on your own to manually upload the fix.
- Exploitation has been attempted in the wild. DigitalOcean’s defense-in-depth controls detected and blocked the activity on its infrastructure, and the identified indicators were shared to help strengthen detection and protection across the ecosystem.
- Keep reading for the full per-edition version table, two narrowly-scoped hotfixes if you cannot upgrade yet, and the Indicators of Compromise (IOC).
The two bugs: CVE-2026-61979 and CVE-2026-15981
The public advisories for both miniOrange SAML 2.0 Single Sign On vulnerabilities cover the free edition only. What follows is DigitalOcean’s own root cause analysis, run against Standard edition 16.1.9, and as far as we can tell it is the first published for any paid edition. Line references shared below come from that work.
CVE-2026-61979: signature algorithm confusion
The miniOrange SAML 2.0 Single Sign On plugin lets the incoming SAML response pick its own signature algorithm. An attacker can exploit this by setting SignatureMethod to HMAC-SHA1. As a result, the plugin allows using the trusted RSA public key PEM as the HMAC secret.
The public key is, by definition, public. The bug works because you:
- Fetch the key from the IdP (Identity Provider) metadata endpoint
- Use it as the HMAC secret
- Sign your own assertion
- The plugin verifies it as genuine
Based on line references from version 16.1.9, the code paths involved include:
Utilities.php:246-250, which reads the attacker-selected algorithm and recasts the RSA key viacastKey()Utilities.php:259-281, which extracts and reloads the public key PEMincludes/lib/SAML2Core/XMLSecurityKey.php:216-218, which enables HMAC-SHA1 as a valid optionincludes/lib/SAML2Core/XMLSecurityKey.php:308-314, which leaves the PEM key material as raw bytes instead of rejecting itincludes/lib/SAML2Core/XMLSecurityKey.php:546-548, which passes that PEM straight intohash_hmac()as the secret
miniOrange fixed this CVE in version 17.0.5 for the Standard edition.
CVE-2026-15981: OpenSSL error treated as a successful verification
openssl_verify() is tri-state, returning 1 for a valid signature, 0 for invalid, and -1 when OpenSSL itself errors out. The plugin loosely checked these results, and in PHP -1 is truthy (valid). So, a malformed signature that trips OpenSSL’s internal error path is accepted as a valid signature.
The bug works because you:
- Craft a SAML response with a malformed signature and send it to the plugin
openssl_verify()hits an internal error and returns -1 instead of 0 or 1- The plugin checks the result as a boolean, and in PHP -1 is truthy
- The plugin verifies it as a valid signature.
Based on line references from version 16.1.9, the code paths involved include:
includes/lib/SAML2Core/XMLSecurityKey.php:486-494returns the raw tri-state resultUtilities.php:252evaluates it as a boolean
miniOrange fixed this CVE in version 17.0.6 for the Standard edition.
There is a third, separate issue that was disclosed shortly after these fixes were made. This issue requires an administrator to click something (UI:R in CVSS terms), so it sits well below these two in practical severity, but it is worth patching in the same pass.
Seven independent plugin versions, under one WordPress slug
miniOrange ships this plugin under one slug, miniorange-saml-20-single-sign-on, which includes seven independently versioned product editions. No two share the same version number.
We asked the vendor for the full breakdown:
| Edition | First version | Latest version | Vulnerable up to | Patched in |
|---|---|---|---|---|
| Free (single site) | 3.0.0 | 5.4.7 | 5.4.4 | 5.4.5 |
| Premium (single site) | 11.3.0 | 13.1.0 | 13.0.3 | 13.0.4 |
| Standard (single site) | 15.1.0 | 17.1.0 | 17.0.5 | 17.0.6 |
| Premium/Enterprise/All-Inclusive (multisite) | 20.0.0 | 20.2.8 | 20.2.7 | 20.2.8 |
| Enterprise/All-Inclusive (single site) | 25.0.0 | 26.1.0 | 26.0.2 | 26.0.3 |
| VIP (single site) | 32.0.0 | 32.0.8 | 32.0.7 | 32.0.8 |
| VIP (multisite) | 35.0.0 | 35.0.7 | 35.0.6 | 35.0.7 |
To determine if your WordPress site is affected, find your edition and check your version against the “vulnerable up to” and “patched in” columns.
Bookmark this table and share it with other WordPress admins in your network.
A few things worth flagging before we move on:
- Each edition spans several major versions: Free covers 3.x to 5.x, Premium 11.x to 13.x, and Standard 15.x to 17.x. A version number on its own does not tell you which edition you are on.
- DigitalOcean confirmed both bugs on 16.1.9, a Standard release from the middle of that line. The fix is 17.0.6: there’s no 16.x patch coming.
- The patched column closes both CVEs. On Free and Standard, the two fixes landed one release apart, with algorithm confusion occurring first. Note that these are the only plans where we have per-CVE detail.
Why no vulnerability database caught these authentication bypasses
A WordPress vulnerability record includes a slug, an affected range, and a fixed version. One range per record assumes every number under a slug climbs together. Here, they climb in seven different directions.
The only public advisory was written about the free edition, which anyone can download from WordPress.org. It affected up to and including 5.4.4, and was fixed in 5.4.5.
While that record is correct, when you apply it to the slug, every paid install carries a higher version number than 5.4.5, so every paid install reads as already patched. Therefore, any WordPress site that was running a vulnerable version like 16.1.9 reported it as patched, along with every other (13.x, 20.x, 26.x, 32.x, and 35.x) vulnerable version.
And widening the range does not rescue it. Stretch the record to 17.0.5 so that a vulnerable 16.1.9 gets caught, and every free-edition site on 5.4.5 or later starts reporting as vulnerable when it is already patched, because 5.4.5 is the smaller number. One range cannot be right for seven version lines at once.
This isn’t a version-matching problem. Because the seven bands never overlap, the affected set can be stated exactly: as seven disjoint ranges on one slug instead of one range stretched across all of them. That’s what the database record carries now. The missing piece all along was the vendor’s table, which had not been published anywhere until now.
This is the actual root cause for this critical gap. Public advisories only covered the Free 3.x to 5.x line because that is what is publicly available on WordPress.org. The additional six editions were patched with no public changelog entry and no public security advisory. This is why paid-edition sites stayed exposed to a critical unauthenticated auth bypass while every database, including ours, showed them as not affected.
It gets worse: No available updates shown in WP dashboard
The remediation story for an affected site is: you do not know you are affected, no vulnerability database tells you that you are, and even if you find out, your WordPress admin dashboard will not show any available update for the affected plugin.
If you are running 16.1.9, your WordPress admin shows no available updates, even though 17.0.6 is available on the same Standard line you already have a license for. The upgrade path from a vulnerable 16.x to a patched 17.x is a manual plugin upload, because the typical WordPress update mechanism does not offer a cross-line jump.
How DigitalOcean found it, and why that matters
There was no advisory to read and no vulnerability database entry flagged the paid edition for these vulnerabilities. The plugin reported itself as fully up to date. In other words, every signal that normally warns of a problem suggested that everything was fine.
So, how did DigitalOcean catch the exploit? It had nothing to do with plugins or versions. An anomalous WordPress administrator session attempt appeared from outside their trusted network and was blocked. The attacker had already used the bypass to obtain a WordPress admin session cookie, but was stalled because the admin panel operations themselves sat restricted behind the trusted network. This is defense in depth doing exactly the job it exists to do.
From there, the DigitalOcean team closed the gap for everyone else. They reproduced the bypass end-to-end on version 16.1.9, traced both bugs to their root causes, specific lines of code in the plugin, and its bundled XML security library. Then, they worked out which paid versions were affected since the vendor hadn’t published these details, wrote the hotfixes (shared below), and shared the whole analysis to be published for public benefit.
Scanning activity against the miniOrange SSO endpoints has been observed from:
207.211.214.41 Brussels, Belgium VPN / datacenter
79.127.224.14 Brussels, Belgium VPN / datacenter
102.91.71.83 Abuja, Nigeria Mobile carrier
162.243.116.148 Secaucus, US Cloud / VPS
84.201.6.54 Frankfurt, Germany Hosting / datacenter
64.225.25.188 Clifton, US Cloud / VPS
The spread suggests opportunistic scanning rather than a targeted campaign. Whoever is running this appears to be throwing the exploit at every site with the plugin installed without checking which edition or version is behind it. This is exactly the behavior that makes the silent-patch situation dangerous. The attacker does not need to know which edition you run, you do.
A public proof of concept for the Free versions exists on GitHub. We won’t be sharing those exploitation steps, because they add nothing defensively that the RCA above does not already provide.
How to protect your WordPress site from CVE-2026-61979 and CVE-2026-15981
There are a few important steps you should take ASAP if you’re using an affected version of the miniOrange SAML 2.0 Single Sign On plugin:
If you can update, update. Look up your edition in the table shared in this article and update the plugin to the version in the patched column, at minimum. Expect to do this by manual upload rather than through the WordPress dashboard, because the update prompt is unlikely to appear.
If you cannot update immediately, you can use small, low-risk hotfixes from DigitalOcean for both bugs.
To fix the algorithm confusion, add this immediately after line 246 in Utilities.php:
if ( XMLSecurityKey::HMAC_SHA1 === $MG ) {
printf( 'HMAC SAML signatures are not supported.' );
exit;
}
To fix the OpenSSL tri-state, replace the return at includes/lib/SAML2Core/XMLSecurityKey.php:494 with:
return openssl_verify( $ql, $hl, $this->key, $MG ) === 1;
Both hotfixes are deliberately narrow. They stop the exploitable path with minimal compatibility risk. They are meant to buy you time, not to replace the vendor fix. A comprehensive fix needs an RSA allowlist for signature algorithms, removal of the public-key recasting path entirely, a hard block on asymmetric keys entering HMAC branches, and general hardening of the bundled XML security library.
Finally, check your logs for authenticated administrator sessions originating from IPs outside your expected ranges. This signal surfaced the vulnerability in the first place, and it does not depend on knowing your plugin version.
The broader lesson
Vulnerability databases are only as good as the version data vendors publish publicly. When a vendor runs seven independently numbered editions under one slug and patches six of them without a public advisory, the entire ecosystem downstream of them goes blind at once: databases, scanners, dashboards, and the site admins relying on all three.
Virtual patching is a genuinely different story, and it is worth being precise about the distinction. A firewall rule that blocks the exploit pattern does not care which edition you run. Protection can cover all seven editions at once, documented or not. Accurate alerting can’t do the same. It only works if it knows exactly what you have installed.
In this instance, protection scaled fine: reporting is what broke.
Credit
All of the original research here belongs to the DigitalOcean security team. Specifically, they:
- Detected and blocked the activity against their own infrastructure, using defense-in-depth
- Confirmed and reproduced the bypass on Standard edition 16.1.9, an edition not covered by any public advisory
- Produced the full root cause analysis for both CVEs on the paid editions, down to specific lines in the plugin and its bundled XML security library
- Identified the fixed versions on the Standard line, 17.0.5 and 17.0.6, which the vendor shipped without a public changelog entry or advisory
- Wrote and validated the hotfixes published in this article
- Shared the indicators of compromise and scanning IPs so the rest of the WordPress security ecosystem could hunt for the same activity
They also chose to publish all of their findings, which is the difference between one company being safe and an entire critical ecosystem getting a fighting chance.
Patchstack’s role revolved around the important follow-up actions: working with miniOrange for the complete edition and version breakdown, then adding the affected ranges into the vulnerability database once we had it.


