fix(auth): reject unusable JWT payloads before session admission - #3325
Chris0Jeky wants to merge 2 commits into
Conversation
Validate object-shaped UTF-8 payloads and representable NumericDates before storage or session use. Preserve the existing missing-expiry policy, handle epoch zero explicitly, and add focused regression coverage and an evidence note.
|
Publication/qualification checkpoint for exact head
This is a draft checkpoint, not full-matrix qualification or merge approval. The branch remains draft until the exact-head required workflow and independent review are complete. |
|
Exact-head qualification is complete for
The PR is being moved to ready-for-review. Green CI is qualification evidence, not merge authorization; independent review remains required. |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Independent Codex review completed on exact head |
Chris0Jeky
left a comment
There was a problem hiding this comment.
Grok mini-review (COMMENT only — not an approval)
Summary
Tight client-side JWT admission harden: strict UTF-8 decode, object-only payloads, Date-representable exp, and exp: 0 treated as present/expired instead of absent. Same gate on persist + restore. Scope stays in jwt.ts / tokenStorage.ts + regressions — no crypto/signature claim, which matches the PR boundary.
Hosted CI on the head looks green (frontend unit Linux/Windows, API integration, E2E smoke, SAST/secrets).
Watch / nits
- Malformed → expired.
isTokenExpirednow returnstruewhen parse fails (was effectively “not expired” via missingexp). Right security posture; just confirm session restore doesn’t thrash logout/retry on a single corrupt stored token (the newgetTokencleanup path looks like it covers that). - Missing-
expstill non-expiring. Unchanged policy, called out in the evidence note — worth a human eyes-on before merge if any issuer can omitexp. - Not authZ. Admission ≠ verification. Fine as written; don’t let green CI read as “tokens are trusted.”
No blockers from this pass.
Summary
Validates UTF-8 JSON object payloads and optional Date-representable NumericDates at the existing shared JWT admission boundary.
Previously, primitive and array payloads were admitted, non-ASCII claims were decoded as binary text, and wrong-type or out-of-range
expvalues could reachDate.toISOString()and throw during session setup.exp: 0was also treated as if the claim were absent.This change:
expto be a finite number representable by JavaScriptDate;Scope
Five files only. No signature-verification claim, server authentication or authorization change, DTO/route/schema/migration/dependency/workflow change, or persisted-data migration.
Base:
307c3b8b50bec1cb0bfaea3e570a942bcb1d4451Exact source head:
a37539a42427e1b1fa8d0e63205b00a23fc6434bRed/green evidence
A supplemental runner imports the actual production modules:
main: 24 expected behavioral failures, 5 controls passing;The coverage includes non-object payloads, unusable expiry values, epoch zero, fractional and Date-boundary NumericDates, UTF-8 claims, malformed UTF-8, persistence refusal and restoration cleanup.
Verification
35595799861: success.35595800181: success.35595800176: success across Linux/Windows frontend lint, typecheck, build and full coverage tests; backend unit/API integration on both platforms; architecture, migrations, containers, dependency/SAST/secret scans, docs governance, worktree contracts and E2E smoke.Ready for independent review. Green CI is not merge authorization. Review should pay particular attention to the unchanged missing-expiry policy, malformed-token expiry behavior and client-side-versus-cryptographic boundary.
Rollback is a normal commit revert; no data migration is required.