Skip to content

fix(verify): validate clockTolerance is a non-negative number#1036

Open
abhu85 wants to merge 1 commit into
auth0:masterfrom
abhu85:fix/clockTolerance-validation
Open

fix(verify): validate clockTolerance is a non-negative number#1036
abhu85 wants to merge 1 commit into
auth0:masterfrom
abhu85:fix/clockTolerance-validation

Conversation

@abhu85

@abhu85 abhu85 commented Jun 22, 2026

Copy link
Copy Markdown

Problem

verify() performs no validation on the clockTolerance option, yet it is added directly to the timestamp comparisons:

if (payload.nbf > clockTimestamp + (options.clockTolerance || 0)) { ... }
if (clockTimestamp >= payload.exp + (options.clockTolerance || 0)) { ... }

When clockTolerance is an invalid value, this silently corrupts the exp/nbf checks instead of erroring:

  • Infinityexp + Infinity === Infinity, so clockTimestamp >= Infinity is always false → an expired token is accepted with no error.
  • NaN → every comparison is false → same silent bypass.
  • a numeric string (e.g. "5") → exp + "5" becomes string concatenation, producing nonsensical comparisons.
  • a negative number → narrows the validity window in a way that is almost certainly a mistake, with no signal to the caller.

This was reported in #1021.

Fix

Validate clockTolerance up front and reject invalid values, mirroring the existing clockTimestamp must be a number guard a few lines above:

if (options.clockTolerance !== undefined &&
    (typeof options.clockTolerance !== 'number' || !Number.isFinite(options.clockTolerance) || options.clockTolerance < 0)) {
  return done(new JsonWebTokenError('clockTolerance must be a non-negative number'));
}

Scope / non-goals

The original report also suggested capping clockTolerance at a fixed maximum (e.g. 300s). I deliberately did not add an upper bound: a large-but-finite tolerance is an unusual-but-legitimate configuration, and a hard cap would be a breaking change for anyone relying on it. This PR only rejects values that are unambiguously invalid (non-number / NaN / Infinity / negative) and cause silent, surprising behavior. If the maintainers want a maximum, that is a separate policy decision and easy to layer on top.

Test plan

  • Added option: clockTolerance tests in test/verify.tests.js (rejects string / negative / non-finite; confirms an expired token is rejected rather than silently accepted with Infinity; confirms a valid small tolerance still verifies).
  • New tests fail on master (4/5) and pass with the fix.
  • npm test (full suite + lint) passes: 516 passing, 1 pending, no regressions.

Fixes #1021

A non-number, NaN, Infinity, or negative `clockTolerance` silently
corrupted the exp/nbf expiry checks. For example `clockTolerance:
Infinity` makes `clockTimestamp >= exp + clockTolerance` always false,
so an expired token is accepted with no error. Reject invalid values up
front, mirroring the existing `clockTimestamp` validation.
@abhu85 abhu85 requested a review from a team as a code owner June 22, 2026 15:03
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.

Bug: clockTolerance accepts arbitrarily large values, bypassing exp verification entirely

1 participant