Skip to content

fix(isJWT): validate header and payload decode to valid JSON objects#2689

Open
abhu85 wants to merge 2 commits intovalidatorjs:masterfrom
abhu85:fix/2511-isJWT-validate-json
Open

fix(isJWT): validate header and payload decode to valid JSON objects#2689
abhu85 wants to merge 2 commits intovalidatorjs:masterfrom
abhu85:fix/2511-isJWT-validate-json

Conversation

@abhu85
Copy link
Copy Markdown

@abhu85 abhu85 commented Mar 16, 2026

Summary

  • Fixes isJWT to properly validate that JWT header and payload decode to valid JSON objects
  • Adds test cases for previously incorrect validations (e.g., foo.bar.baz, .babelrc.cjs)
  • No breaking changes - only rejects strings that were incorrectly accepted before

Problem

The current isJWT validator only checks if the three dot-separated parts are valid Base64, but doesn't verify that the decoded header and payload are valid JSON objects as required by RFC 7519.

This causes false positives:

isJWT('foo.bar.')  // true (incorrect - "foo" is not valid JSON)
isJWT('.babelrc.cjs')  // true (incorrect)
isJWT('..')  // true (incorrect)

Solution

Per RFC 7519, a JWT consists of:

  1. Header - MUST be a JSON object (contains alg, typ, etc.)
  2. Payload - MUST be a JSON object (the claims)
  3. Signature - Binary data (not required to be JSON)

The fix adds JSON parsing validation for the header and payload parts after Base64 decoding, ensuring they are valid JSON objects (not arrays, strings, or other types).

Test Plan

  • All existing tests pass (317 passing)
  • Added test cases for issue examples (foo.bar.baz, .babelrc.cjs, .., .t.)
  • Linting passes
  • Coverage maintained at 99%+

Compatibility

  • No breaking changes for valid JWTs
  • Backwards compatible - only rejects previously invalid inputs
  • Works in both Node.js and browser environments

Fixes #2511

…ects (validatorjs#2511)

The isJWT validator now properly validates that the header (first part) and
payload (second part) of a JWT decode to valid JSON objects, not just valid
Base64 strings.

Per RFC 7519, a JWT consists of three Base64URL-encoded parts:
- Header: MUST be a JSON object containing at least "alg"
- Payload: MUST be a JSON object (the claims)
- Signature: Binary data (not required to be JSON)

Previously, strings like "foo.bar.baz" or ".babelrc.cjs" would incorrectly
return true because they matched the Base64 pattern, even though decoding
them does not produce valid JSON.

Fixes validatorjs#2511

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (88e0d3d) to head (1602dfb).
⚠️ Report is 6 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #2689   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          114       114           
  Lines         2590      2612   +22     
  Branches       659       664    +5     
=========================================
+ Hits          2590      2612   +22     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Adds tests for 100% coverage of the new isValidJSONObject function:
- Edge cases for JSON types that aren't objects (arrays, null, primitives)
- Buffer.from() fallback path (when atob is unavailable)
- Fallback return false path (when neither atob nor Buffer available)

Fixes validatorjs#2511 coverage requirements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens isJWT validation to ensure JWT header and payload are not only Base64URL-encoded, but also decode into valid JSON objects, addressing false positives reported in #2511.

Changes:

  • Add Base64URL decode + JSON-object parsing validation for JWT header and payload in isJWT.
  • Extend isJWT invalid-case test coverage to include Base64-valid but non-JSON / non-object JSON decoded segments.
  • Add tests for decoder fallback behavior when atob and/or Buffer are unavailable.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/lib/isJWT.js Adds decoded JSON-object validation for JWT header/payload after Base64URL checks.
test/validators.test.js Adds regression tests for false positives and decoder-fallback paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if (typeof atob === 'function') {
decoded = atob(base64);
} else if (typeof Buffer !== 'undefined') {
decoded = Buffer.from(base64, 'base64').toString('utf8');
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isValidJSONObject uses Buffer.from(...), but this library declares support for Node >=0.10 (where Buffer.from does not exist). In those runtimes typeof Buffer !== 'undefined' will be true, then Buffer.from throws, and valid JWTs will be rejected. Consider feature-detecting Buffer.from and falling back to new Buffer(base64, 'base64')/Buffer(base64, 'base64') when Buffer.from is unavailable (while keeping the browser atob path).

Suggested change
decoded = Buffer.from(base64, 'base64').toString('utf8');
if (typeof Buffer.from === 'function') {
decoded = Buffer.from(base64, 'base64').toString('utf8');
} else {
// Fallback for older Node.js versions (e.g., Node 0.10) where Buffer.from is unavailable
decoded = new Buffer(base64, 'base64').toString('utf8');
}

Copilot uses AI. Check for mistakes.
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.

isJWT does not check whether the decoded sections are valid JSON

2 participants