Skip to content

fix: reject a non-numeric clockTolerance instead of silently ignoring it - #1045

Open
afonsojanu wants to merge 1 commit into
auth0:masterfrom
afonsojanu:fix/verify-reject-invalid-clock-tolerance
Open

fix: reject a non-numeric clockTolerance instead of silently ignoring it#1045
afonsojanu wants to merge 1 commit into
auth0:masterfrom
afonsojanu:fix/verify-reject-invalid-clock-tolerance

Conversation

@afonsojanu

Copy link
Copy Markdown

Closes #606.

verify() checks that clockTimestamp is a number, but there was never an equivalent check for clockTolerance. If you pass a string there, which is easy to do by accident since maxAge accepts strings, the exp/nbf comparisons turn into string concatenation instead of arithmetic. Infinity and NaN break the same comparisons in their own way. All three cases end up making the tolerance effectively unbounded, so a token that's actually expired still verifies fine.

Repro before this change:

const token = jwt.sign({foo: 'bar'}, 'secret', {expiresIn: -100}); // expired 100s ago
jwt.verify(token, 'secret', {clockTolerance: '5'}, console.log); // no error, token accepted

The fix just validates clockTolerance the same way clockTimestamp already is, and throws a JsonWebTokenError instead of letting it silently do the wrong thing. Added tests covering the string, Infinity and NaN cases, plus one confirming a normal numeric tolerance still works as before.

There was an earlier attempt at this back in #611, but it never got merged and had its own bug (the validation lived inside a .forEach callback, so returning from it didn't actually stop verify(), it just kept going). This is a fresh, smaller fix that doesn't have that problem.

verify() already validates that clockTimestamp is a number, but never did
the same check for clockTolerance. Passing a string there (something you
can easily do by accident, since maxAge does accept strings) turns the
internal exp/nbf comparisons into string concatenation, and Infinity or
NaN break the same arithmetic in their own way. In all three cases the
tolerance effectively becomes unbounded, so an already-expired token gets
accepted as valid no matter how old it is.

This mirrors the existing clockTimestamp check and throws a
JsonWebTokenError up front instead of letting the comparison quietly do
the wrong thing.
@afonsojanu
afonsojanu requested a review from a team as a code owner September 3, 2026 09:07
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.

Entering a string value for clockTolerance causes expired tokens to be accepted

1 participant