There are many ways for an application to fail securely, and there are a few memorable ways for it to fail catastrophically. CVE-2026-29000 belongs in the second category. It is not a cosmetic JWT bug, not a narrow parser edge case, and not a misconfiguration that only matters in a lab. It is a critical authentication bypass in pac4j-jwt, specifically in the JwtAuthenticator flow for encrypted JWTs, where an attacker who possesses the server’s RSA public key can craft a JWE-wrapped PlainJWT with arbitrary claims and authenticate as any user, including an administrator. The official affected ranges are all versions prior to 4.5.9, 5.7.9そして 6.3.3, and the project has already published those patched releases. (NVD)
That single sentence is already enough to explain why security engineers should care. Authentication is the control plane for everything that comes later: authorization, tenancy separation, administrative actions, API access, audit confidence, and incident response scoping. If the identity layer accepts a forged principal, downstream controls do not save you. They faithfully enforce permissions for an attacker who is now wearing a valid-looking identity badge. CISA’s MS-ISAC summary put it plainly: successful exploitation can let an unauthenticated remote attacker authenticate as any user, including administrators, with any role, without knowing a secret. (CIS)
What makes this bug especially important is the shape of the trust failure. The attacker does not need the private key. The attacker does not need a leaked HMAC secret. The attacker does not need a phished session cookie. The attacker needs the RSA public key, which is often intentionally distributed because it is supposed to be public, plus a token structure that causes the library to trust decrypted claims before a signature has actually been verified. That is why this vulnerability has been described by GitHub as Critical with a 10.0 CVSS score, while NVD currently shows the CNA’s 9.3 CVSS v4 score during its enrichment process. (ギットハブ)
What CVE-2026-29000 actually is
CVE-2026-29000 is a cryptographic signature verification failure in the JwtAuthenticator component of pac4j-jwt when handling encrypted JWTs. The public description is consistent across the authoritative sources. NVD states that affected versions allow remote attackers to forge authentication tokens and that attackers who possess the server’s RSA public key can create a JWE-wrapped PlainJWT with arbitrary subject and role claims, bypassing signature verification and authenticating as any user, including administrators. GitHub’s advisory mirrors that description and lists the patched versions as 4.5.9, 5.7.9そして 6.3.3. The pac4j project’s own security advisory says the same thing operationally: upgrade now, with no ambiguity about target versions. (NVD)
The weakness is classified as CWE-347, Improper Verification of Cryptographic Signature. That classification matters because this is not merely a token parsing problem. It is a decision problem. The software reaches a point where it should answer the question, “Has this token proven identity?” and under a certain execution path the answer effectively becomes “yes” before the required proof has happened. That is the kind of bug that collapses security boundaries cleanly and quietly. (オープンCVE)
The current public record also shows that proof-of-concept material is available. MS-ISAC notes that PoC code has been made available by the reporting team, and HKCERT likewise states that PoC exploit code is public. That raises the urgency from patch-soon to patch-now, especially for internet-facing identity and SSO-adjacent services. (CIS)
Why this vulnerability is more serious than many JWT bugs
Security teams have seen JWT mistakes before, and that familiarity can be dangerous. A lot of token bugs live in the realm of bad defaults, weak algorithm handling, or unsafe application-specific assumptions. CVE-2026-29000 is more severe because it lives directly in a core authentication flow and because the exploit input looks structurally legitimate enough to survive the early stages of processing. The token is not random junk. It is an encrypted container that the server can decrypt. The failure happens because decryption is incorrectly allowed to stand in for identity proof. (CodeAnt AI)
That distinction is worth dwelling on. Encryption answers the question, “Who can read this?” Signature verification answers the question, “Who created this, and has it been modified?” Those are not interchangeable guarantees. A system that treats successful decryption as evidence of legitimate authorship is already on the edge of an identity-layer collapse. In the pac4j case, the attacker can construct an unsigned inner token, encrypt it with the server’s public key, and rely on the vulnerable logic path to treat the decrypted claims as trustworthy. (CodeAnt AI)
This is exactly why modern identity bugs often do outsized damage. They do not need to break crypto primitives outright. They only need to exploit the distance between what one security layer guarantees and what the surrounding system assumes it guarantees. When that gap appears inside authentication code, even a cleanly implemented RBAC system becomes a permissioning engine for forged principals. (CodeAnt AI)
The core exploit logic, without the mythology
To understand the exploit, it helps to simplify the intended processing flow.
A secure encrypted-and-signed token pipeline should look conceptually like this:
receive token
→ decrypt outer JWE layer
→ inspect inner token type
→ verify signature on signed content
→ validate issuer, audience, time-based claims, and algorithm policy
→ map claims to identity
→ authorize actions
The vulnerable path effectively becomes something closer to this:
receive token
→ decrypt outer JWE layer
→ trust inner claims
→ build authenticated profile
That is the entire disaster. The attacker does not need to beat cryptography. The attacker only needs to feed the library a token shape that causes the signature verification step not to run in the way the application developer assumes it will. CodeAnt’s technical writeup describes the practical exploitation model in three simple steps: create an unsigned JWT with arbitrary claims, encrypt it using the server’s public RSA key, and submit it as an authentication credential. Because the system trusts the decrypted token before ensuring signature-backed authenticity, the attacker can authenticate as any user. (CodeAnt AI)
In other words, the exploit does not turn encryption into a breaking primitive. It turns encryption into a false signal of legitimacy.

JWE, JWS, and PlainJWT — the distinction that decides whether your auth layer works
A lot of production incidents happen because engineering teams know the acronyms but not the trust model.
A JWS is about integrity and origin authenticity. It is signed. The signature is the mechanism that lets the server decide whether the token was produced by an authorized signer and whether the claims were altered.
A JWE is about confidentiality. It is encrypted. It protects token contents from being read by parties that do not hold the decryption key.
A PlainJWT is unsigned. It is a JWT structure without cryptographic proof of origin.
These three facts matter because a JWE container can hold content that is confidential but not authenticated in the way your application expects. If the implementation path allows a decrypted PlainJWT to proceed as though it were a verified signed token, the system has confused secrecy with identity. The CodeAnt analysis explicitly frames the pac4j issue this way: the system successfully decrypted the token, but because the payload contained a PlainJWT, the signature verification step never executed. (CodeAnt AI)
For engineers, this is the practical lesson: token processing has to be explicit about token type, allowed algorithms, expected nesting, and what security property each layer is supposed to provide. “It parsed” is not a trust signal. “It decrypted” is not a trust signal. “It verified under the expected signer and policy” is the trust signal. (CodeAnt AI)
Affected versions, patch targets, and immediate action table
The published fix guidance is refreshingly straightforward.
| Line | 影響を受けるバージョン | Fixed version | 優先順位 |
|---|---|---|---|
| 4.x | earlier than 4.5.9 | 4.5.9 | Immediate |
| 5.x | earlier than 5.7.9 | 5.7.9 | Immediate |
| 6.x | earlier than 6.3.3 | 6.3.3 | Immediate |
This version guidance is confirmed by NVD, GitHub Advisory Database, and the pac4j project’s own advisory. (NVD)
One important nuance from GitHub’s advisory is that the affected range for the 6.x line is expressed as >= 6.0.4.1, < 6.3.3, and the 5.x line begins at >= 5.0.0-RC1, < 5.7.9, while older 4.x releases are vulnerable below 4.5.9. For operational triage, treat the official patched versions as the minimum acceptable target and verify the actual package pulled into your build, not just what your top-level pom.xml appears to declare. (ギットハブ)
That last point matters because ecosystem exposure is rarely limited to direct dependencies. Sonatype has already highlighted that the pac4j issue extends through additional packages that pull in the vulnerable component transitively, and multiple public advisories are explicitly warning teams to check bundled or downstream products, not just standalone pac4j-jwt installs. (Security Boulevard)
Where pac4j tends to show up, and why transitive exposure matters
The pac4j project positions itself as a Java security framework supporting many frameworks and tools, including JEE, Spring Web MVC, Spring WebFlux, Spring Security, CAS server, Play, Vert.x, Spark Java, Ratpack, JAX-RS, Dropwizard, Javalin, Undertow, and others. That does not mean every one of those stacks is automatically vulnerable, but it does mean the library sits in a part of the ecosystem where transitive dependency risk is realistic. (pac4j.org)
This is where identity-layer vulnerabilities become operationally annoying. Teams often know whether they use a given framework, but they do not always know whether a vulnerable auth component is being pulled in through a platform module, identity adapter, or packaged integration. That is why vendor responses like Appian’s are useful signals even when they are not your vendor: Appian published a specific note saying it investigated the issue and determined it was not impacted because pac4j-jwt is not used in Appian Cloud or Appian products. The important part is the process model. Vendors are having to verify component presence, not merely CVE headlines. (Appian Community)
For enterprise teams, the right immediate question is not “Do we use pac4j?” It is “Where in our authentication path could org.pac4j:pac4j-jwt exist directly or transitively, and do any of those services accept encrypted JWTs?” That is a very different inventory problem, and it needs SBOM-aware dependency inspection rather than grep-based optimism. (Security Boulevard)

Real-world impact, not just abstract severity
The best way to understand this bug is to map it to the systems people actually run.
If a vulnerable service uses pac4j-jwt to turn token claims into application identities, an attacker may be able to mint arbitrary サブ, 役割, or tenant claims and arrive at the application as a legitimate principal. Depending on how claims are mapped, that can become admin-console access, cross-tenant data access, privileged API calls, or trusted automation actions executed under forged service identities. Those are not hypothetical categories; they are exactly the kinds of outcomes expected from “authenticate as any user, including administrator, with any role.” (CIS)
The danger is also cumulative. An authentication bypass at the edge of a service can poison audit trails because the logs now show authenticated activity under a forged but structurally valid identity. Incident responders may chase the wrong user account. Authorization reviews may conclude that permissions behaved correctly, which is technically true and operationally useless. In multi-service environments, a forged identity accepted at one boundary can be propagated inward as a trusted caller. (CIS)
That is why security teams should resist the temptation to interpret the low availability impact in some scoring models as reassurance. A bug that primarily compromises identity and integrity is still an incident-grade issue, especially when authentication sits upstream of secrets, data stores, control planes, or tenant isolation. (ギットハブ)
The engineering lesson is not “JWT is bad”
The wrong takeaway from identity bugs is usually the loudest one. In this case, the lazy reaction would be to say that JWT is inherently unsafe. That is not the useful lesson.
The real lesson is that token systems become fragile when engineering teams compress several separate security questions into one boolean outcome. Can I decrypt it? Did it parse? Does it contain expected claims? Is it signed? Is it signed by the correct key? Is the algorithm permitted? Is the token type one my application allows? Is this nested structure one I intentionally support? These are separate checks. A secure implementation does not treat them as vibes. It treats them as hard gates. (CodeAnt AI)
CodeAnt’s code-level explanation calls this a composition vulnerability, and that description is useful. The JWT specification allows PlainJWT. Nimbus behaves as designed. A null check can be correct in isolation. But if the control flow allows those pieces to compose into “decrypt token, trust payload, authenticate user,” the system has removed authentication from the authentication process. (CodeAnt AI)
This is why mature security reviews should focus less on whether each primitive is “used” and more on whether each primitive’s guarantee is mapped to the right trust decision. That is where many modern auth bugs hide.
How to verify exposure safely in your own environment
The right first move is dependency verification, not panic patching by rumor. Start by identifying whether org.pac4j:pac4j-jwt is present directly or transitively.
For Maven:
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-jwt</artifactId>
<version>6.3.3</version>
</dependency>
For a quick dependency-tree check:
mvn dependency:tree | grep pac4j
For Gradle:
./gradlew dependencies --configuration runtimeClasspath | grep pac4j
Then answer four operational questions. First, is the vulnerable package present in any deployed service? Second, do those services process encrypted JWTs, not just signed ones? Third, is there any identity or role mapping directly from token claims into application privileges? Fourth, are there downstream services or products bundling pac4j components where you rely on vendor patch cadence rather than your own package management? The package fix is necessary, but exposure depends on the runtime path. (ギットハブ)
Because public PoC details exist, validating in a controlled staging environment is reasonable, but the safe objective is confirmation of fix effectiveness, not creation of a red-team trophy. In practice, that means verifying that unsigned inner tokens are rejected, that nested-token policy is explicit, and that decryption success alone never produces an authenticated profile. (CIS)

Detection ideas for defenders
There is no single universal detection rule for a library logic bug, but there are several practical signals worth instrumenting.
If your application logs JWT metadata, capture whether the token path involved JWE, what the declared algorithm was, whether the inner token type was signed or plain, and whether signature verification actually executed before identity construction. If your logs cannot answer that last question, your observability around the auth layer is weaker than it should be. (CodeAnt AI)
At the application and API boundary, look for anomalous jumps in privilege-bearing claims, especially 役割, groups, or tenant-scoping claims that do not line up with your identity provider’s issuance patterns. Sudden admin activity from identities that were not recently provisioned, or role sets that do not match your normal IdP mappings, should be treated as potentially suspicious. This is not specific to pac4j, but auth-bypass incidents tend to reveal themselves through privilege shape anomalies before they reveal themselves through exploit fingerprints. That is an inference based on how the vulnerability changes trust decisions, not a vendor-published IOC. (NVD)
At the dependency layer, feed your SBOM and artifact inventory into whatever governance tooling you already trust. GitHub Advisory, Snyk, and similar databases have already published fixed-version guidance for the Maven package, which makes automated identification of exposed builds relatively straightforward. (ギットハブ)
Hardening patterns that outlive this CVE
Patching to the fixed version is the urgent move. Hardening the trust model is the durable one.
A few patterns are worth making explicit in code and review:
| Hardening goal | Practical control |
|---|---|
| Never trust encryption as proof of identity | Separate decryption from authentication in code structure |
| Eliminate unsigned-token ambiguity | Reject PlainJWT unless there is an explicit, reviewed business requirement |
| Reduce algorithm confusion risk | Use strict algorithm allowlists and bind verification to expected key type |
| Reduce hidden nesting risk | Make nested JWT support explicit, not automatic |
| Improve auth observability | Log token class, algorithm, signer expectation, and verification outcome |
| Reduce supply-chain surprise | Continuously inventory direct and transitive auth dependencies |
These are not theoretical best practices. They map directly onto the failure mode exposed by CVE-2026-29000 and onto the broader family of JWT trust-boundary bugs seen across ecosystems. (CodeAnt AI)
A design rule I like for code review is simple: no path should ever go from “token parsed” to “principal built” without a clearly auditable authentication decision in between. If that state transition is implicit, hidden in helper behavior, or dependent on token class assumptions, you are relying on luck.
Related CVEs that show the same security pattern
CVE-2026-29000 is new, but the trust failure it exposes is old.
One of the classic JWT failures is CVE-2015-9235その jsonwebtoken algorithm-confusion issue. In that case, a system could be tricked into treating a token signed under a symmetric algorithm as valid where an asymmetric verification mode was expected. The common theme is not identical code but identical architectural damage: the system accepts a token under the wrong trust assumptions and turns attacker-controlled claims into authenticated identity. (NVD)
A more recent example is CVE-2024-54150 で cjwt, where algorithm confusion could cause the wrong verification method to be used, including using a public key as an HMAC secret, potentially allowing unauthorized access. Again, the shared lesson is that token validation bugs are rarely about syntax. They are about the system attaching the wrong security meaning to a token that it is technically able to process. (NVD)
That is why the pac4j bug deserves attention beyond the Java ecosystem. It is another case study in how identity systems break when the code handling token structure, cryptographic checks, and application trust decisions is not brutally explicit about boundaries.

A safe testing mindset for security teams
Because this is an authentication-layer issue, testing discipline matters. The goal is not to prove you can pop your own login page for sport. The goal is to answer three controlled questions:
- Is the vulnerable package present?
- Is the vulnerable execution path reachable in the way your application uses tokens?
- Does the patched version actually eliminate acceptance of unsigned nested claims?
A good staging validation plan uses a non-production environment, test identities, and synthetic role mappings. It verifies rejection behavior under malformed or unsigned nested structures and confirms that patched services either fail closed or surface explicit verification errors. Since public exploit material exists, there is no value in improvising unsafe experiments against production. The value is in proving your boundary is fixed and your observability is good enough to spot regressions later. (CIS)
Identity-layer vulnerabilities are deceptively hard to operationalize because the bug itself may live in one library while the real risk lives in a distributed graph of applications, API gateways, SSO adapters, and downstream services that trust claims. The painful part for defenders is usually not reading the CVE. It is discovering where that auth path actually exists, which internet-facing systems expose it, and which assets deserve immediate validation first.
That is where a platform like Penligent can help in a way that feels natural rather than forced. When the vulnerable component sits on an authentication boundary, teams need asset discovery, auth-surface mapping, dependency-aware prioritization, exploitability validation in controlled scopes, and evidence-backed reporting for engineering and leadership. Those are exactly the workflows that turn a scary identity CVE into a fixable security program task rather than a vague library panic. (寡黙)
There is also a practical reporting benefit. Identity bugs often produce deceptively “normal” application behavior because the forged principal looks legitimate once accepted. Tools that can tie exposed assets, reachable auth surfaces, reproduced findings, and remediation evidence into one workflow save time during the patch window and reduce the risk of false closure.
最後の収穫
CVE-2026-29000 is a reminder that the most dangerous authentication failures do not always look dramatic in code. Sometimes the system decrypts the token, the parser is happy, the claims look well formed, and the app continues as if nothing unusual happened. But identity security lives in the difference between “this token can be read” and “this token has proven who created it.”
In the pac4j-jwt vulnerability, that difference collapsed. A public key became enough to produce a token the system would trust. That is why this issue matters. It is not another generic JWT headline. It is a clean example of how modern auth stacks fail when confidentiality, structure, and authenticity are allowed to blur together.
Patch to 4.5.9, 5.7.9あるいは 6.3.3 immediately if you are affected. Then go one step further: review your token trust model as if this bug had happened in your own codebase, because next time it may.
Recommended reading
- NVD entry for CVE-2026-29000
- CVE.org record for CVE-2026-29000
- GitHub Advisory Database, GHSA-pm7g-w2cf-q238
- pac4j official security advisory
- MS-ISAC advisory via CIS
- Snyk advisory for org.pac4j:pac4j-jwt
- NVD entry for CVE-2015-9235
- NVD entry for CVE-2024-54150
- CVE-2026-29000, The pac4j-jwt Authentication Bypass That Turns Encryption Into a False Sense of Trust
- pac4j-jwt Security Risks, CVE-2026-29000, and What Secure JWT Validation Really Requires
- CVE-2026-29000 in pac4j-jwt, an identity bypass hiding behind encryption
- Penligent Hacking Labs

