Skip to content

fix: properly validate JWT signatures in verifyJwt#762

Open
adityabhatkar23 wants to merge 1 commit into
LabsCrypt:mainfrom
adityabhatkar23:fix/jwt-signature-verification
Open

fix: properly validate JWT signatures in verifyJwt#762
adityabhatkar23 wants to merge 1 commit into
LabsCrypt:mainfrom
adityabhatkar23:fix/jwt-signature-verification

Conversation

@adityabhatkar23

Copy link
Copy Markdown
Contributor

Description

This PR fixes a critical security vulnerability in the JWT verification function where tampered signatures were being accepted as valid tokens. The verifyJwt function now properly validates JWT signatures and returns null for any verification failure.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧪 Test addition or update

Related Issues

Fixes #761

Changes Made

  • Added explicit length check before timingSafeEqual to prevent timing attacks and buffer length mismatches
  • Improved base64url decoding with proper error handling to catch malformed signatures
  • Added explicit null checks for payload.exp to handle missing or invalid expiration claims
  • Enhanced error handling in the try-catch block to ensure tampered signatures always return null

The verifyJwt function now properly validates:

  • JWT signature integrity using HMAC-SHA256
  • Token expiration claims
  • Proper JWT structure (header.payload.signature format)
  • Malformed or corrupted token parts

Testing

Test Coverage

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed

Test Steps

  1. Run the backend test suite: pnpm test -- tests/auth-jwt.test.ts
  2. Verify that all JWT validation tests pass, including:
    • "round-trips through verifyJwt" - valid tokens are accepted
    • "returns null for a tampered header" - malformed header is rejected
    • "returns null for a tampered body" - modified payload is rejected
    • "returns null for a tampered signature" - invalid signature is rejected
    • "returns null for an expired token" - expired tokens are rejected
    • "returns null for a malformed token missing dots" - incomplete tokens are rejected
    • "returns null for an entirely fabricated string" - garbage input is rejected
  3. Run full CI suite to ensure no regressions

Breaking Changes

None. This is a bug fix that strengthens security without changing the public API or expected behavior for valid tokens.

Screenshots/Demo

N/A - Backend security fix

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published
  • I have checked for breaking changes and documented them if applicable

Additional Notes

This fix addresses a critical security vulnerability where the JWT signature verification was not properly enforcing signature validation. The implementation now uses crypto.timingSafeEqual() with proper length checking to prevent timing attacks and malformed tokens from being accepted. The fix ensures that any tampering with the JWT (header, payload, or signature) will result in verification failure and return null as expected.

Ensure tampered signatures are rejected and return null as expected.
Add explicit length checks and base64url error handling.

Fixes: LabsCrypt#761
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] verifyJwt accepts tampered signature — returns publicKey instead of null

1 participant