Skip to content
RESEARCH INDEX BREACHROAD / INTELLIGENCE NOTE

oidcc 3.9.0 and CVE-2026-75759: an encrypted unsigned token enabled account takeover

An Erlang OIDC library accepted a JWE carrying attacker-authored claims without a nested signature. Here is why encryption is not sender authentication.

PUBLIC RESEARCH
AUTHOR
/ CEO Breachroad · OSCP · PNPT
PUBLISHED
30 August 2026
READING TIME
19 min read
TOPIC
Identity and Access
oidcc 3.9.0 and CVE-2026-75759: an encrypted unsigned token enabled account takeover

The oidcc project published an advisory for CVE-2026-75759 on 30 August. The Erlang and Elixir OpenID Connect library accepted an encrypted but unsigned token as successfully verified. In deployments processing encrypted ID tokens or JARM responses, an attacker could author arbitrary claims, encrypt them with the application’s public key and impersonate a chosen user without the identity provider’s signing key.

The flaw has a CVSS 4.0 score of 7.6 (High). It affects oidcc from 3.2.0-beta.1 up to, but not including, 3.9.0 and is fixed in 3.9.0. Not every OIDC client using the library exposes the path: encrypted ID tokens or encrypted JARM authorisation responses must be in use. Where those prerequisites hold, however, the result can be unauthenticated account takeover.

The case is instructive because cryptography was present and operational. There was no weak cipher, stolen key or broken encryption. The system confused message confidentiality with proof of who created the message.

JWS, JWE and Nested JWT provide different properties

JWT is a claims container, not an automatic authenticity guarantee. JWS adds a signature or MAC so that a recipient can verify integrity and origin. JWE encrypts content for a recipient and protects confidentiality. A relying party’s public encryption key may intentionally be available in JWKS so that a sender can construct a JWE.

Encrypting data with the recipient’s public key does not authenticate the sender. Anyone possessing that public key can create a new encrypted message. OpenID Connect Core therefore requires an encrypted ID token to be signed first and encrypted second. The result is a Nested JWT: the outer JWE gives confidentiality and the inner JWS proves that the expected issuer approved the claims.

Claims such as iss, aud, sub, exp and nbf become meaningful only after authenticity has been established. Comparing iss with an expected URL does not help if the attacker wrote the entire claims set. A correct aud likewise provides no issuer proof.

Where oidcc validation failed

The advisory identifies oidcc_jwt_util:verify_decrypted_token/4. After decryption, the library attempted to interpret the plaintext as a signed JWS. When that operation returned invalid_jwt_token, meaning the content was not signed at all, the error was swallowed. The code parsed the claims and returned success with none in place of a verification key.

oidcc_token:int_validate_jwt/4 then selected a success path based on the JOSE structure type rather than evidence that a signature had been verified. The outer JWE satisfied that branch. Subsequent issuer, audience and time checks operated over attacker-authored data.

This is a classic fail-open pattern: failure of a mandatory control became an alternate accepted format. A structure type was allowed to stand in for proof that a security step had completed.

Two reachable paths: ID token and JARM

The first path is an encrypted ID token. An attacker needs the client’s public encryption key and acceptable alg and enc parameters. They can construct claims with the genuine iss and aud but a victim’s sub, leave them unsigned and encrypt them for the relying party. The affected library returned those claims as validated.

The second path concerns JWT Secured Authorization Response Mode (JARM). JARM wraps an authorisation response in a JWT to protect data travelling over the front channel. Its processing rules require signature verification unconditionally. The advisory states that the vulnerable JARM path is reachable through the browser, so exploitation does not depend on controlling a server-to-server connection.

UserInfo is not affected in the same sense. OpenID Connect Core permits an encrypted UserInfo response without an additional signature. The maintainer enforced the signature requirement in the two callers that require it rather than globally rejecting a valid UserInfo form.

That distinction matters for regression testing. A simplistic rule that every JWE must contain a JWS would break a legitimate protocol case. The correct rule is contextual: the signature requirement follows the message semantics and governing specification.

Who should respond first

Find BEAM services using oidcc directly or through an authentication library. Confirm the version in mix.lock, rebar.lock, the SBOM and the running release. In a service estate, do not assume that a common base image implies a common application dependency version.

Next inspect discovery metadata and client configuration. Are id_token_encrypted_response_alg or id_token_encrypted_response_enc set? Does the provider advertise encrypted responses? Does the client use JARM with authorization_signed_response_alg or response-encryption settings? Is the relying party’s public encryption key exposed in public JWKS?

A public encryption key is not a misconfiguration. It is a normal asymmetric-cryptography property. Any security model that depends on a public key remaining secret is already wrong. The risk arose because oidcc treated encryption to that key as a substitute for an issuer signature.

Prioritise applications where sub maps directly to privileged accounts and login produces a long-lived session or a downstream access token. The blast radius includes every data set and action available to the impersonated identity, not just the login component.

Upgrade, retest and session invalidation

Upgrade to oidcc 3.9.0 or a later compatible version. Rebuild and redeploy the release, verifying that the lockfile and final artefact contain the corrected package. Restarting without rebuilding does not change dependency code.

A positive test should prove that a correctly signed and encrypted ID token continues to work. A negative test should demonstrate rejection of a JWE containing claims without an inner JWS. For JARM, cover a signed response, an unsigned response, the wrong issuer or audience, an expired value and an algorithm outside the allowlist. A plain signed-JWT test is insufficient because it never traverses the faulty post-decryption branch.

If a vulnerable configuration was internet-accessible, consider invalidating sessions created during the exposure window. Rotating the identity provider’s signing key does not remediate this flaw because the attack never needed it. Rotating the relying party’s encryption key may prevent reuse of previously prepared artefacts, but patching and session analysis remain the primary controls.

Detection and incident analysis

The most valuable signal is a token with an outer JWE whose decrypted content lacks the compact JWS required for an ID token or JARM response. If an identity gateway records validation outcomes, look for successful results with no verification-key identifier. Do not place complete tokens in ordinary logs; they may contain personal data and may themselves be credentials.

Correlate new sessions using encrypted-token configurations with unusual logins to existing sub values, abrupt device or location changes, absence of corresponding authentication history at the IdP and sensitive actions immediately after session creation. A relying-party session without a matching provider authentication event is a particularly useful lead.

After confirmed misuse, invalidate sessions, preserve application and IdP records, identify the impersonated accounts’ permissions and analyse every action in their context. A signature-validation defect can become a data breach or a business-process integrity incident.

Architectural lesson: represent validation outcomes explicitly

Security code should not pass around a loose structure where none can mean both “signature permitted to be absent” and “signature verification did not happen”. A safer design separates explicit outcomes such as verified_signature, permitted_unsigned_message and rejected. The caller then specifies which outcome its protocol message requires.

Regression suites should also cross format with semantics: JWS, JWE containing Nested JWT, JWE containing raw claims, ID token, UserInfo and JARM. A JOSE parser may decode all of them correctly while the authorisation decision still needs to understand the message’s meaning.

Source facts and Breachroad conclusions

The mechanism, affected range, 3.9.0 fix, reachable paths and score come from the maintainer advisory, the Erlang Ecosystem Foundation CNA and NVD. Prioritisation, telemetry and response guidance are Breachroad conclusions. The primary sources do not report confirmed in-the-wild exploitation of CVE-2026-75759.

Primary sources

Token validation is a business decision grounded in cryptography, not merely format parsing. Our cybersecurity training helps teams reason about identity, session and protocol boundaries. OIDC implementations, callbacks and authorisation can be examined more deeply in a web and API penetration test.

SHARE / COPY