Skip to content

fix: reject zero-length HMAC secrets in sign and verify - #1053

Open
ricardoBLabs wants to merge 1 commit into
auth0:masterfrom
ricardoBLabs:harden-empty-secret
Open

ricardoBLabs wants to merge 1 commit into
auth0:masterfrom
ricardoBLabs:harden-empty-secret

Conversation

@ricardoBLabs

Copy link
Copy Markdown

Description

jwt.sign() and jwt.verify() already reject an empty string secret (secretOrPrivateKey must have a value / secret or public key must be provided). A zero-length Buffer or a zero-length secret KeyObject gets past that check, because it is truthy and crypto.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 a KeyObject, HS* algorithms reject a key with symmetricKeySize === 0 with the existing secretOrPrivateKey must have a value error.
  • verify.js: same check, with the existing secret or public key must be provided error. It also covers keys returned by a secret callback.
  • The check only applies to HS* algorithms, so 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 for sign and verify.
  • test/empty_secret.tests.js: tests for an empty string, a zero-length Buffer (explicit HS256 and default algorithm), a zero-length KeyObject, the callback forms, a secret callback that returns an empty Buffer, and regression tests for none and non-empty Buffer secrets. If a Node.js version rejects zero-length keys in createSecretKey(), the input is already rejected as invalid key material, so the tests accept either message and skip the KeyObject cases.

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

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 the sign.js/verify.js change, 8 of the 12 new tests in test/empty_secret.tests.js fail. Other Node.js versions are left to CI.

  • This change adds test coverage for new/changed/fixed functionality

Checklist

  • I have added documentation for new/changed functionality in this PR or in auth0.com/docs
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not the default branch

🤖 Generated with Claude Code

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reject zero-length Buffer/KeyObject secrets for HS* algorithms, like empty strings

1 participant