feat!: v4 — TypeScript port, zero deps, timing-safe HMAC, fix CVE-202… - #34
Merged
Conversation
…3-48238 Fixes CVE-2023-48238 (JWT algorithm confusion, GHSA-4xw9-cx39-r355). The v3 decode trusted whatever header.alg the token declared, allowing an attacker with the server's RSA public key to craft a token with alg:HS256 whose signature is an HMAC keyed by that public key. v4 now classifies the key handed in (PEM-encoded vs plain secret) and refuses to verify when it doesn't match the algorithm family. The same guard runs on encode to catch developer misuse. An optional { algorithms: string[] } allowlist on decode adds a second layer for safety-conscious callers. Other security and quality improvements: - HMAC verify uses crypto.timingSafeEqual on length-checked Buffers instead of the v3 string === compare. - alg: "none" continues to be rejected on both encode and decode. - Defensive parsing: tokens whose decoded header is not a JSON object, or whose alg is not a string, are rejected. Tooling: - TypeScript source under src/, dual ESM+CJS+types output via tsup - vitest replaces mocha + nyc (43 tests, 100% coverage) - Biome replaces standard (tabs, width 4) - GitHub Actions matrix on Node 20/22/24 replaces Travis - pnpm as the package manager, engines >=18 Runtime deps dropped (all 4): - base64-url → Buffer.from(s, "base64url") / .toString("base64url") - is.object → inline plain-object brand check - json-parse-safe → native try { JSON.parse } catch - xtend → object spread (defaultHeader still wins on conflict) Public API: - encode(key, data, [algorithm], [cb]) — unchanged - decode(key, token, [options], [cb]) — options is new and optional - getAlgorithms() — unchanged - JWTError — now a real class extending Error - Named exports; require('json-web-token') returns { encode, decode, getAlgorithms, JWTError } as in v3 BREAKING CHANGE: engines bumped to Node >=18. BREAKING CHANGE: HS256 paired with a PEM key (or any RS256 paired with a plain secret) is now rejected by both encode and decode. Tokens crafted to exploit CVE-2023-48238 will no longer verify.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…3-48238
Fixes CVE-2023-48238 (JWT algorithm confusion, GHSA-4xw9-cx39-r355). The v3 decode trusted whatever header.alg the token declared, allowing an attacker with the server's RSA public key to craft a token with alg:HS256 whose signature is an HMAC keyed by that public key. v4 now classifies the key handed in (PEM-encoded vs plain secret) and refuses to verify when it doesn't match the algorithm family. The same guard runs on encode to catch developer misuse. An optional { algorithms: string[] } allowlist on decode adds a second layer for safety-conscious callers.
Other security and quality improvements:
Tooling:
Runtime deps dropped (all 4):
Public API:
BREAKING CHANGE: engines bumped to Node >=18.
BREAKING CHANGE: HS256 paired with a PEM key (or any RS256 paired with a plain secret) is now rejected by both encode and decode. Tokens crafted to exploit CVE-2023-48238 will no longer verify.