Full Report
CodeAnt AI is a AI assisted code review platform. They were scanning open-source repositories for CVE patches and checking whether the patches actually fixed the claimed vulnerability. Since patches are sometimes wrong, this is a good way to find bugs. While reviewing the code, the AI tool flagged a null check within signedJWT directly before the signature verification block. If the signedJWT is not null, then verify the signature. Otherwise, do nothing. In the case of an exception in Java, the code exited. So, what does toSignedJWT() normally return? toSignedJWT() will try to parse the decrypted payload as a signed JWT. If it's a PlainJWT, which is an unsigned token, it returns null. Using this type completely bypasses JWT verification. They found another issue in simple git using a similar type of analysis. This bug was a case-sensitivity issue in a regex that allowed a bypass of two previous patches. The bug is interesting, but the blog post was somewhat misleading and poorly written from a technical standpoint. Although it's a good bug, it felt more like marketing and introductory-level analysis. "Look at us" and "look at the impact" were the vibes of the post.
Analysis Summary
# Vulnerability: Critical Authentication Bypass in pac4j-jwt via Signature Skip
## CVE Details
- **CVE ID:** CVE-2026-29000
- **CVSS Score:** 10.0 (Critical)
- **CWE:** CWE-347 (Improper Verification of Cryptographic Signature) / CWE-287 (Improper Authentication)
## Affected Systems
- **Products:** pac4j-jwt (Java authentication library)
- **Versions:**
- 4.x versions prior to 4.5.9
- 5.x versions prior to 5.7.9
- 6.x versions prior to 6.3.3
- **Configurations:** Deployments utilizing encrypted JWTs (JWE) where the application expects a nested signed JWT (JWS).
## Vulnerability Description
The vulnerability exists in the `JwtAuthenticator.java` component. When processing an encrypted token (JWE), the code attempts to decrypt the payload and then extract an inner signed JWT using the `toSignedJWT()` method.
The security flaw is a logic error: the signature verification block is wrapped in a null check (`if (signedJWT != null)`). If the decrypted payload is a `PlainJWT` (an unsigned token) rather than a `SignedJWT`, the `toSignedJWT()` method returns `null`. This causes the entire signature verification routine to be skipped silently. The application then proceeds to create an authenticated user profile based on the unverified claims in the `PlainJWT`.
## Exploitation
- **Status:** PoC described; vulnerability confirmed by maintainer.
- **Complexity:** Low
- **Attack Vector:** Network
- **Technical Requirement:** An attacker only needs the server's RSA public key (which is intended to be public) to wrap a malicious `PlainJWT` inside a JWE. Because the server can decrypt the JWE using its own private key, it accepts the unverified inner payload as valid.
## Impact
- **Confidentiality:** High (Attacker can impersonate any user)
- **Integrity:** High (Attacker can forge any claims/roles)
- **Availability:** High (Attacker can gain administrative access)
## Remediation
### Patches
The maintainer has released the following patched versions:
- **Version 4.5.9**
- **Version 5.7.9**
- **Version 6.3.3**
### Workarounds
No specific configuration workarounds were provided; immediate upgrade to the patched library versions is strongly recommended due to the severity of the bypass.
## Detection
- **Indicators of Compromise:** Review authentication logs for successfully processed JWTs that lack a signature header or contain unexpected claims.
- **Detection methods and tools:** Audit code for usages of `pac4j-jwt` and verify the library version against the vulnerable ranges listed above.
## References
- **Vendor Advisory:** hxxps://www[.]pac4j[.]org/blog/security-advisory-pac4j-jwt-jwtauthenticator[.]html
- **Research Post:** hxxps://www[.]codeant[.]ai/security-research/pac4j-jwt-authentication-bypass-public-key