Repository navigation
fix: reject zero-length HMAC secrets in sign and verify - #1053
Open
ricardoBLabs wants to merge 1 commit into
Open
ricardoBLabs wants to merge 1 commit into
ricardoBLabs wants to merge 1 commit into
Conversation
An empty string secret is already rejected, but a zero-length Buffer or an empty secret KeyObject is truthy and passes the existing guard. Reject a zero-length symmetric key for HS* algorithms after key conversion, using the existing error messages. The `none` algorithm is unaffected. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Description
jwt.sign()andjwt.verify()already reject an empty string secret (secretOrPrivateKey must have a value/secret or public key must be provided). A zero-lengthBufferor a zero-length secretKeyObjectgets past that check, because it is truthy andcrypto.createSecretKey()accepts it. The HS256/HS384/HS512 code then signs and verifies with an empty HMAC key.This usually comes from configuration rather than intent, for example a secret read from an empty file (
fs.readFileSync(path)) or decoded from an unset variable (Buffer.from(process.env.JWT_SECRET ?? '', 'base64')). Today these calls succeed silently, and anyone can compute valid tokens for that key. With this change they fail in the same way an empty string does.Changes
sign.js: after the key is converted to aKeyObject, HS* algorithms reject a key withsymmetricKeySize === 0with the existingsecretOrPrivateKey must have a valueerror.verify.js: same check, with the existingsecret or public key must be providederror. It also covers keys returned by a secret callback.algorithm: 'none'with an empty secret behaves as before (see Fix breaking change on 7.4.2 for empty secret + "none" algorithm (sync code style) #386).README.md: one sentence each forsignandverify.test/empty_secret.tests.js: tests for an empty string, a zero-lengthBuffer(explicit HS256 and default algorithm), a zero-lengthKeyObject, the callback forms, a secret callback that returns an emptyBuffer, and regression tests fornoneand non-emptyBuffersecrets. If a Node.js version rejects zero-length keys increateSecretKey(), the input is already rejected as invalid key material, so the tests accept either message and skip theKeyObjectcases.Compatibility
An application that currently signs or verifies HS* tokens with a zero-length key will now get an error. That is the intended behaviour, and it matches what already happens with
''.References
noneregression)Buffer('')accepted where''is rejected)Testing
npm test(lint and mocha) on Node.js 24 (linux/arm64 container). Before the change the suite had 511 passing and 1 pending; with it, 523 passing and 1 pending. Without thesign.js/verify.jschange, 8 of the 12 new tests intest/empty_secret.tests.jsfail. Other Node.js versions are left to CI.Checklist
🤖 Generated with Claude Code