OAuth CVE-2026-19349, 72887 and 72888: userless state, a lost verifier and an unbounded cache
Three LemonLDAP::NG and Net::OAuth flaws show how state, oauth_verifier and pre-auth dispatch semantics can quietly move an SSO trust boundary.
- AUTHOR
- Karol Rapacz / Breachroad CEO · OSCP · PNPT
- PUBLISHED
- 16 August 2026
- READING TIME
- 16 min read
- TOPIC
- Identity and Access
Three records connected by identity-protocol design, though affecting two independent projects, were published on 16 August 2026. CVE-2026-19349 describes an authentication bypass in LemonLDAP::NG’s GitHub and LinkedIn modules. CVE-2026-72887 covers a silent OAuth 1.0a-to-1.0 downgrade in the Perl Net::OAuth::Client library, while CVE-2026-72888 concerns an unbounded cache of signature-method names in Net::OAuth before request verification.
The first two issues damage login-flow integrity. In LemonLDAP, a state-session identifier could act as an ordinary SSO session. In Net::OAuth, a provider response without callback confirmation disabled 1.0a and removed oauth_verifier from the token exchange. The third demonstrates that code running “before authentication” still needs resource budgets and a strict allowlist.
These CVEs do not form one attack chain and do not affect one common OAuth implementation. Their combined educational value is nevertheless strong: a state token, verifier and algorithm name are not generic strings. Each field has a role in a protocol state machine, and silently moving it to a weaker meaning can remove the control an application expected.
CVE-2026-19349: state stored as an SSO session
LemonLDAP::NG is an SSO access-management gateway. Before redirecting to an identity provider, the affected GitHub and LinkedIn authentication modules created a session for the state parameter. The call to the session function supplied positional values where the function expected an identifier followed by named pairs. The session type consequently defaulted to an ordinary SSO session rather than short-lived protocol state.
Its identifier was then handed to the unauthenticated client in the redirect URL. According to the CVE-2026-19349 record, a visitor could present it as a session cookie. The session contained neither _user nor authenticationLevel, but the shipped default => accept rule could still allow it into a virtual host.
Not every LemonLDAP deployment is exposed. The GitHub or LinkedIn authentication module must be enabled, and access rules must accept an empty session without checking the user or authentication level. Configurations that explicitly require identity and a suitable authenticationLevel provide a stronger second barrier.
Affected branches are 2.0.0 before 2.16.9, 2.17.0 before 2.21.5 and 2.22.0 before 2.23.3. Fixes are available in 2.16.9, 2.21.5 and 2.23.3. Administrators should choose the newest supported release on their branch rather than transplanting one change without end-to-end login tests.
Why state is not a user session
In OAuth and OpenID Connect, state ties the beginning of a flow to its completion and helps protect against CSRF and transaction confusion. It may be stored server-side, but that state record should have a distinct namespace, short lifetime and one-time semantics, and it must not grant resource access.
A user session has opposite semantics: it is presented across requests as evidence of completed authentication. Sharing a storage engine is not inherently wrong, but record types and consumer validation must prevent role confusion. A high-entropy identifier provides no protection when the system itself discloses it to the client as part of the protocol.
Access control must therefore ask more than “does this session exist?”. A gateway needs to verify the user, expected authentication mechanism, assurance level, lifecycle stage and expiry. Incomplete state should fail closed rather than become an anonymous session accepted by a default rule.
CVE-2026-72887: OAuth 1.0a silently returns to 1.0
OAuth 1.0a introduced oauth_verifier to bind user authorisation to the later exchange of a request token for an access token. Without that binding, classic OAuth 1.0 was vulnerable to session fixation. An application selected 1.0a in Net::OAuth::Client by configuring a callback.
The project advisory shows that a provider response without oauth_callback_confirmed disabled that mode with no exception or warning. The library then constructed its request through the OAuth 1.0 class, which had no verifier parameter, so a verifier supplied by the application disappeared from the message.
It is important to identify the relevant attacker correctly. A malicious OAuth provider already controls its own account system and gains little from downgrading itself. The meaningful case is an incomplete or older provider that omits confirmation, allowing a third party to exploit the restored OAuth 1.0 session-fixation weakness: obtain a request token, induce the victim to authorise it, then finish the exchange in an attacker-controlled session.
Net-OAuth releases before 0.32 are affected; 0.32 contains the correction. An application declaring 1.0a should fail closed. Missing callback confirmation is not a compatibility negotiation but failure to satisfy a required security condition.
CVE-2026-72888: cache growth before signature checking
Net::OAuth dynamically chooses the class implementing a signature method. Its smart_require helper memoised every class name in a process-global hash, including names whose loading failed. The class name came from the client’s signature_method parameter and was resolved before the signature was verified.
The second Net::OAuth advisory describes monotonic memory growth in a persistent Perl process. An unauthenticated client could submit unique, long names. Each remained cached for the worker’s lifetime and also caused a module search and string-eval compilation.
Header limits constrain cost when the value comes from Authorization, but a POST path may have a different limit. A reverse proxy therefore does not replace library validation. The strongest correction allowlists supported signature methods before dynamic dispatch, caches only successfully loaded classes and bounds the entire request.
What teams should do now
LemonLDAP::NG administrators should confirm whether GitHub or LinkedIn authentication is enabled, update the relevant branch and inspect access rules. Every protected host should require a specific identity or authentication level. An anonymous accept rule must not guard a resource the organisation considers authenticated.
After updating, invalidate suspicious and incomplete sessions when the store cannot reliably distinguish their type. Review logs for sessions without a user that reached protected hosts and for unusual reuse of a state identifier as a cookie. Do not add raw tokens to logs; a safe identifier digest and session type are sufficient.
Net::OAuth users should move to 0.32 or later. An integration test must simulate missing oauth_callback_confirmed and expect a controlled failure, not a successful fallback. A server test should reject an unknown signature method before dynamic class loading and demonstrate stable worker memory.
Inventory applications still using OAuth 1.0a. The protocol is old but remains in integrations that rarely receive security review. A Perl package SBOM, cpanfile analysis and production-image inspection can reveal a library copy absent from the main application repository.
Designing a safer flow
Every protocol artefact needs an explicit type and stage. A state record must never pass a user-session validator. The callback should consume state exactly once, bind it to the initiating browser, verify the provider and only then create a new authenticated session.
Security-version negotiation should be monotonic: a component may reject a weak partner, but it must not silently disable a protection requested by the application. If compatibility requires an older protocol, the choice should be explicit, constrained to one provider and accompanied by its own risk assessment.
Pre-authentication code should use allowlists and constant-cost operations. A network-derived class, algorithm or handler name is dangerous even if a signature is checked later. Input validation must precede expensive dispatch and writes to long-lived caches.
Facts and Breachroad conclusions
It is a fact that CVE-2026-19349 affects LemonLDAP::NG’s GitHub and LinkedIn modules and is fixed in 2.16.9, 2.21.5 and 2.23.3. Both Net::OAuth issues affect releases before 0.32 and are fixed in 0.32. The sources do not establish widespread active exploitation.
Breachroad’s conclusion is that SSO should be treated as a state machine rather than a collection of random tokens. The most dangerous failures occur when a cryptographically strong identifier is accepted in the wrong role or a requested control disappears through automatic fallback.
Teams responsible for login and integrations can explore these patterns in our cybersecurity training for organisations. Session, callback and authorisation boundaries can also be reviewed through web application and API penetration testing.


