Skip to content

fix: re-validate GitHub OAuth token every 24h to detect revocation (GHSA-6c5j-4w43-2v8f #2)#594

Closed
advikdivekar wants to merge 9 commits into
Priyanshu-byte-coder:mainfrom
advikdivekar:fix/ghsa-token-revocation-check
Closed

fix: re-validate GitHub OAuth token every 24h to detect revocation (GHSA-6c5j-4w43-2v8f #2)#594
advikdivekar wants to merge 9 commits into
Priyanshu-byte-coder:mainfrom
advikdivekar:fix/ghsa-token-revocation-check

Conversation

@advikdivekar
Copy link
Copy Markdown
Contributor

Problem

The NextAuth jwt callback stored the GitHub OAuth access token at sign-in and never re-validated it. The account object is only populated on the first sign-in event — every subsequent JWT refresh skipped that block entirely. The 30-day JWT continued to hold and submit a revoked token for its full lifetime with no detection.

A user who revoked DevTrack's access via GitHub Settings had no way to actually invalidate the session — DevTrack kept appearing authenticated and kept submitting the revoked token as Authorization: Bearer on every API call for up to 30 days.

Root cause: No periodic token validation in the jwt callback. The error field was absent from type declarations, so there was no type-safe path to signal revocation downstream.

What changed

src/lib/auth.ts

  • On initial sign-in, stamps token.accessTokenValidatedAt = Date.now() alongside the access token
  • On every subsequent JWT callback: if more than 24 hours have elapsed since last validation, makes a single lightweight GET /user call to the GitHub API
    • 401 response → sets token.error = "TokenRevoked"
    • 200 response → updates token.accessTokenValidatedAt, clears any prior error
    • Network error or GitHub 5xx → session left intact (no false evictions)
  • session callback now surfaces token.error into session.error

src/types/next-auth.d.ts

  • Added error?: string to the Session interface
  • Added accessTokenValidatedAt?: number and error?: string to the JWT interface

src/app/dashboard/page.tsx

  • After the null-session check, redirects to /?error=TokenRevoked when session.error === "TokenRevoked"

How to verify

  1. Sign in to DevTrack with a GitHub account
  2. Go to GitHub Settings → Applications → Authorized OAuth Apps → DevTrack → Revoke
  3. Return to /dashboard without signing out — within 24 hours the page redirects to /?error=TokenRevoked
  4. TypeScript: session.error compiles without type error across the codebase
  5. Network failure during token check: session preserved, no redirect

Regression check

  • Normal sign-in and dashboard use: unaffected (validation triggers only after 24h)
  • All API routes reading session.accessToken: unchanged
  • SESSION_MAX_AGE and SESSION_UPDATE_AGE: unchanged

Fixes GHSA-6c5j-4w43-2v8f vulnerability #2 (High).

- Wrap req.json() in try/catch — returns 400 on malformed JSON
- Validate body is a non-null object before destructuring
- title: must be non-empty string, trimmed, max 100 characters
- target: must be integer in [1, 10000] — blocks 0, negatives, floats, NaN, overflow
- unit: clamped to 30 chars silently
- recurrence: unknown values default to 'none' explicitly
- All bounds defined as named constants

Fixes division-by-zero (target:0 → Infinity% progress bar) and
negative target making 0-progress goals show as 100% complete.

Closes Priyanshu-byte-coder#454
JWT callback now stamps accessTokenValidatedAt on sign-in and makes a
lightweight GET /user call every 24 hours. A 401 response sets
token.error = "TokenRevoked"; the dashboard redirects to /?error=TokenRevoked
so users are prompted to re-authenticate. Network errors and GitHub 5xx
responses leave the session intact. Type declarations updated to include
error and accessTokenValidatedAt on Session and JWT interfaces.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 21, 2026

@advikdivekar is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added gssoc26 GSSoC 2026 contribution type:bug GSSoC type bonus: bug fix type:security GSSoC type bonus: security (+20 pts) labels May 21, 2026
@github-actions
Copy link
Copy Markdown

GSSoC Label Checklist 🏷️

@Priyanshu-byte-coder — please apply the appropriate labels before merging:

Difficulty (pick one):

  • level:beginner — 20 pts
  • level:intermediate — 35 pts
  • level:advanced — 55 pts
  • level:critical — 80 pts

Quality (optional):

  • quality:clean — ×1.2 multiplier
  • quality:exceptional — ×1.5 multiplier

Validation (required to score):

  • gssoc:approved — counts for points
  • gssoc:invalid / gssoc:spam / gssoc:ai-slop — does not score

Type labels (type:*) are auto-detected from files and title. Review and adjust if needed.
Points formula: (difficulty × quality_multiplier) + type_bonus

@advikdivekar
Copy link
Copy Markdown
Contributor Author

Closing — patch will be submitted through the private advisory fork (GHSA-6c5j-4w43-2v8f) to avoid public disclosure before coordinated release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc26 GSSoC 2026 contribution type:bug GSSoC type bonus: bug fix type:security GSSoC type bonus: security (+20 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant