Net::SAML2 made a trust anchor mandatory on July 30 after a signature-verification bypass. Five weeks later, a downstream Perl module has its own CVE for constructing the binding without one.
What happened
CPANSec published CVE-2026-86304 late on Sunday, September 6, 2026. NVD carried the record at 11:17 p.m. UTC, in Received status, with no CVSS score. The description is one sentence: “MojoX::Authentication versions before 0.006 for Perl allow SAML authentication bypass because parse_assertion builds Net::SAML2::Binding::POST without a trust anchor.”
The record names the exact code: MojoX::Authentication::Model::SAML2::parse_assertion, in lib/MojoX/Authentication/Model/SAML2.pm. It is classified CWE-347, Improper Verification of Cryptographic Signature, with CAPEC-115, Authentication Bypass, as the impact. Everything before 0.006 is affected; 0.006 is the fix.
What makes this worth reading is the reference the CNA attached to it: CVE-2026-18089, published August 3, 2026, against Net::SAML2 itself. That record reads: “Net::SAML2 versions before 0.86 for Perl allow SAML authentication bypass by verifying responses against the response-embedded certificate in verify_xml when no trust anchor is configured.” It is classified CWE-347 and CWE-295, and the affected range is everything below 0.86.
So the library had a mode in which it would validate a SAML response’s signature against a certificate carried inside that same response. An attacker signs an assertion with a certificate they generated, embeds the certificate, and the signature checks out. The assertion can name any NameID it likes.
What the upstream fix actually did
Net::SAML2 0.86 shipped on Thursday, July 30, 2026 as a security release closing three CVEs — CVE-2026-18089, CVE-2026-18092, and CVE-2026-18108. Its changelog states that “one of cacert, cert_text or insecure_trust_embedded_cert must be provided when instantiating” the core modules. The 0.88 changelog, dated the same evening, puts it more plainly: “a trust anchor (cacert or cert_text) is now required to verify a Response or Assertion.” Version 0.87 was never released; 0.86 went out with an incorrect version number in lib/Net/SAML2.pm, which is why 0.88 exists at all.
That is a good fix, and it is worth being precise about why. The maintainer did not add a warning or flip a default. He made the omission fatal at construction time, and gave the unsafe behavior an argument name — insecure_trust_embedded_cert — that a caller cannot pass by accident or defend in review. A library that silently trusted whatever certificate arrived in the message now refuses to start without being told what it should trust.
It also means that from July 30 onward, every caller that never configured a trust anchor was in one of two states. On Net::SAML2 below 0.86, it was quietly accepting forged assertions. On 0.86 or later, it was dying at instantiation. Neither is a working login flow, and the second is the only one an operator would notice.
MojoX::Authentication was one of those callers. Its parse_assertion built a Net::SAML2::Binding::POST with no trust anchor, which is precisely the configuration CVE-2026-18089 describes and precisely the configuration 0.86 refuses. Version 0.006 fixes it. The gap between the upstream CVE and this downstream one is five weeks.
The other record in the same batch
CPANSec published a second Perl authentication bypass in the same window. CVE-2026-86219, also in NVD as of September 6 in Received status with no CVSS, covers Authen::SASL::Perl::DIGEST_MD5 before 2.2100, classified CWE-294, Authentication Bypass by Capture-replay. The record’s language: “An attacker who observes one successful qop=auth exchange can replay the captured response against a later session for the same service, host, realm and user, and authenticate as that user without knowing the password.” The cause is that server_step never checks that the nonce the client returned is the nonce the server sent. The fix is in 2.2100, and the patch is a single public commit in the perl-authen-sasl repository, so the change is inspectable rather than described.
Why it matters
The useful lesson here is not that a small CPAN module had a bug. It is the shape of what happens after a library hardens a dangerous default.
Signature verification in federated authentication is nearly always structured as an option. The library will check a signature either way; the only question is what it checks against. When the answer defaults to “whatever the message brought with it,” the failure is silent in both directions — no error, no log line, no failed test. An integration written against that default passes its test suite, works in staging against a real identity provider, and works in production, because a legitimate IdP also embeds its certificate. Nothing distinguishes the safe case from the unsafe one until someone signs their own assertion.
This publication has now covered several instances of the same structure in a month: python-jose still accepting a public key as an HMAC secret because the earlier fix checked the key’s format rather than its role; F5’s nginx-saml parsing attacker-controlled XML before deciding whether it was allowed to; three WordPress plugins re-expanding shortcodes after core had already escaped the input. In each case the guard existed and ran. It was pointed at the wrong thing.
What is different about Net::SAML2 is that the maintainer’s response closed the class rather than the instance, and the cost of that shows up here. A hard failure at instantiation is the correct engineering choice, and it converts a security problem into an availability problem for exactly the callers who were vulnerable. Downstream maintainers then have to be found, one distribution at a time, by whoever is auditing. CVE-2026-86304 is the first of those to surface with its own identifier. There is no reason to assume it is the only caller that built the binding without a trust anchor, and there is no mechanism in CPAN — or in npm, or PyPI — that enumerates them for you. The dependency graph knows which distributions use Net::SAML2. It does not know which of them pass cacert.
On scale, be clear: MojoX::Authentication is a small single-maintainer CPAN distribution, not a deployed product with an install base anyone has published. If you are not running it, this specific CVE is not your problem. The question it should prompt is the transferable one — whether anything in your estate consumes a SAML library with the trust anchor left unset, in Perl or anywhere else.
What to do
If you run MojoX::Authentication, upgrade to 0.006 or later.
If you use Net::SAML2 directly, be on 0.88. Not 0.86, which shipped with a wrong version number in lib/Net/SAML2.pm, and not 0.87, which does not exist. Then confirm you are passing cacert or cert_text, and grep your codebase for insecure_trust_embedded_cert — if that argument appears anywhere, someone silenced the new requirement instead of satisfying it, and the original bypass is still live in your application.
If you run Authen::SASL server-side with DIGEST-MD5, upgrade to 2.2100. If you cannot, DIGEST-MD5 has been formally obsolete since RFC 6331 in 2011; moving that service to SCRAM or to SASL over TLS is the durable answer.
More generally, audit the callers rather than the library version. A SAML integration that is on a patched library and still constructs its binding without a trust anchor is not fixed — before July 30 it was silently exploitable, and after it, it fails loudly. Either way it needs the anchor.
Sourcing note
Checked: the CVE Program’s CNA records for CVE-2026-86304 and CVE-2026-18089, both published by CPANSec, read directly from the CVE Services API; the NVD API records for both plus CVE-2026-86219; and the Net::SAML2 upstream Changes file from the project’s own repository, which is the source for the 0.86 and 0.88 release dates and for the quoted trust-anchor requirement.
Not reached: metacpan.org disallows automated fetching, so the CPANSec references pointing at MojoX-Authentication 0.004’s source line 188 and at the 0.006 release notes could not be read directly. The claim that parse_assertion builds the binding without a trust anchor rests on CPANSec’s record, which names the file, the routine, and the line. The Authen::SASL patch commit is public on GitHub and was not read line by line for this piece.
Unresolved: neither new record carries a CVSS score, a CWE from NVD, or CPE data, so neither will surface in version-matching tooling in its current state. No download or install figures for MojoX::Authentication were obtainable, so its real reach is unquantified here rather than estimated. Whether other Net::SAML2 consumers have the same defect is unknown; no coordinated downstream audit has been announced.
