CVE-2026-44699: Verified Repro With Script Download
CVE-2026-44699: libjwt: JWT algorithm-confusion authentication bypass via RSA JWK without alg
CVE-2026-44699 is verified against libjwt · c. Affected versions: >= 3.0.0, <= 3.3.2. Fixed in 3.3.3. Vulnerability class: Auth Bypass. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00139.
What Is CVE-2026-44699?
CVE-2026-44699 is a critical (CVSS 9.1 per the advisory) JWT algorithm-confusion authentication bypass (CWE-347) in libjwt, a C library for JWT processing. An RSA JWK lacking an alg parameter can be forged into a valid HMAC-signed token using only the public JWKS. Pruva reproduced it (reproduction REPRO-2026-00139).
CVE-2026-44699 Severity & CVSS Score
CVE-2026-44699 is rated critical severity, with a CVSS base score of 9.1 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected libjwt Versions
libjwt · c versions >= 3.0.0, <= 3.3.2 are affected.
How to Reproduce CVE-2026-44699
pruva-verify REPRO-2026-00139 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00139/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-44699
Reproduced by Pruva's autonomous agents — 106 tool calls over 13 min. Full root-cause analysis and the complete transcript are below.
How the agent worked
Root Cause and Exploit Chain for CVE-2026-44699
Summary
libjwt versions 3.0.0 through 3.3.2 suffer from an algorithm confusion attack that allows JWT forgery using only a public RSA JWK. When an RSA JWK lacking an alg parameter is supplied as the verification key for an HMAC-signed token (HS256/HS384/HS512), the library incorrectly accepts the RSA key for HMAC verification. Because the internal jwk_item_t union shares storage between provider_data (an RSA EVP_PKEY*) and oct.{key,len} (HMAC bytes/length), the HMAC path reads a zero-length key and produces a successful verification for any token signed as HMAC("", header.payload). An attacker who knows only the published JWKS can forge valid tokens and bypass authentication.
Impact
- Package:
libjwt(C library for JWT processing) - Affected versions: 3.0.0 through 3.3.2 (inclusive)
- Fixed version: 3.3.3
- Risk level: Critical (CVSS 3.1 base 9.1)
- Consequences: Full authentication bypass. Any attacker with access to the public JWKS (which is public by definition) can forge HMAC-signed JWTs that the vulnerable library accepts as valid.
Root Cause
The root cause is a failure to validate that a JWK's actual key type (kty) is compatible with the JWT algorithm being used for verification. The library previously relied on the optional alg parameter in the JWK to determine compatibility. When alg was absent (JWT_ALG_NONE), __setkey_check() in jwt-common.c allowed the key to be used with any caller-specified algorithm.
Because jwk_item_t is implemented as a union, setting an RSA key populates provider_data while leaving the HMAC oct fields uninitialized (effectively zero-length). When the HMAC verification backend later runs, it reads oct.key and oct.len, producing an HMAC with an empty key. Since HMAC("", data) is deterministic, an attacker can pre-compute the signature and forge a valid token.
Fix commit
- Commit
49c730ain the libjwt repository: "Fix algorithm confusion that allows JWT forgery via RSA JWK as HMAC key" - The fix introduces
jwt_alg_required_kty()which maps each JWA algorithm to its required JWK key type (e.g.,HS256requireskty=oct). __setkey_check()now rejects any setkey/verify callback that pairs a non-none algorithm with an incompatiblekty.__verify_config_post()adds a defensive re-check oncejwt->algis bound from the token header.__check_hmac()adds a final backstop refusing any non-oct key for HMAC algorithms.
Reproduction Steps
- Execute
repro/reproduction_steps.sh - The script builds two versions of
libjwt:v3.3.2(vulnerable)v3.3.3(fixed)
- It compiles a small C harness against each version.
- The harness:
- parses an RSA public JWK without an
algfield, - calls
jwt_checker_setkey(checker, JWT_ALG_HS256, rsa_jwk), - verifies a forged
HS256token whose signature isHMAC-SHA256("", header.payload).
- parses an RSA public JWK without an
- On the vulnerable build, the forged token verifies successfully (harness exits
0). - On the fixed build,
setkeyis rejected immediately with "Key type does not match algorithm" (harness exits2).
Evidence
Log locations
logs/vuln_out.txt— output from harness linked againstv3.3.2logs/fix_out.txt— output from harness linked againstv3.3.3logs/results.txt— combined summaryrepro/validation_verdict.json— structured verdict
Key excerpts
Vulnerable build (v3.3.2)
Exit code: 0
VERIFY SUCCEEDED (VULNERABLE)
Fixed build (v3.3.3)
Exit code: 2
setkey rejected: Key type does not match algorithm
These outputs confirm the bug and its remediation: the vulnerable library silently accepts an RSA JWK for HMAC verification and validates the forged token, while the fixed library rejects the key/algorithm mismatch at setkey time.
Environment
- OS: Ubuntu Noble (24.04)
- Compiler: GCC 13.3.0
- CMake: 3.28.3
- OpenSSL: 3.0.13
- Jansson: 2.14
- libjwt built from source at
external/libjwt
Recommendations / Next Steps
- Upgrade immediately to
libjwt >= 3.3.3. - Review JWKS handling in applications that use
libjwt. Ensure that verification callbacks do not blindly trust thealgfield from an attacker-controlled JWT header without also checking the JWK'skty. - Regression tests: The fix commit includes a comprehensive test suite in
tests/jwt_security.ccovering RSA, EC, and OKP keys mis-targeted at HMAC algorithms, as well as malformed JWKs wherealgdisagrees withkty. Maintainers should ensure these tests are run in CI. - Defense in depth: Even after upgrading, applications should enforce algorithm whitelisting (e.g., only accept
RS256if the JWKS contains RSA keys) at the application layer to reduce the impact of any future confusion bugs.
Additional Notes
- Idempotency: The reproduction script was run twice consecutively with identical results, confirming the build and test process is deterministic.
- Edge cases: The advisory notes the bug specifically requires an RSA JWK without an
algparameter. An RSA JWK that explicitly declares"alg": "RS256"would also be rejected for HMAC after the fix, because the fix binds algorithm acceptance to the JWK'skty, not its optionalalghint. - Limitations: The reproduction script focuses on
HS256with a 2048-bit RSA JWK. The fix commit's tests confirm the same issue exists forHS384andHS512, as well as for EC and OKP keys misused as HMAC keys.
CVE-2026-44699 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
mkdir -p external && cd external && git clone --depth=100 https://github.com/benmcollins/libjwt.gitCloning into 'libjwt'...
Artifacts and Evidence for CVE-2026-44699
Scripts, logs, diffs, and output captured during the reproduction.
No artifacts available
How to Fix CVE-2026-44699
Upgrade libjwt · c to 3.3.3 or later.
FAQ: CVE-2026-44699
How does the CVE-2026-44699 algorithm-confusion attack work?
Which versions of libjwt are affected by CVE-2026-44699, and where is it fixed?
How severe is CVE-2026-44699?
How can I reproduce CVE-2026-44699?
References for CVE-2026-44699
Authoritative sources for CVE-2026-44699 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.