Skip to content

fix(security): remove GitHub access token from client-exposed session#2875

Open
BCA-krishna wants to merge 2 commits into
Priyanshu-byte-coder:mainfrom
BCA-krishna:fix/issue-2845-secure-token-storage
Open

fix(security): remove GitHub access token from client-exposed session#2875
BCA-krishna wants to merge 2 commits into
Priyanshu-byte-coder:mainfrom
BCA-krishna:fix/issue-2845-secure-token-storage

Conversation

@BCA-krishna

Copy link
Copy Markdown
Contributor

Closes #2845

Problem

The NextAuth session() callback copied the GitHub access token onto
the session object. Since session is exposed to client-side code via
useSession()/getSession(), the raw GitHub token was readable by any
JavaScript running on the page — including a successful XSS payload —
giving full access to the user's GitHub account with the granted scopes.

Fix

  • Removed session.accessToken = token.accessToken from the session()
    callback in src/lib/auth.ts. The token now stays only in the
    encrypted, HttpOnly JWT cookie that NextAuth manages — it never reaches
    the browser.
  • Added a getAccessToken() helper in src/lib/get-session-token.ts
    that reads the token server-side only, directly from the JWT via
    next-auth/jwt's getToken().
  • Migrated all API routes that previously read session.accessToken to
    call getAccessToken() instead (29 route files).
  • Updated/added tests to mock getAccessToken() and to assert that
    accessToken is never present on the session object returned to the
    client.

Testing

  • npm run type-check — 0 errors
  • npm run lint — 0 errors (5 pre-existing unrelated <img> warnings)
  • npm test — same failure count as main (all pre-existing/unrelated
    to this change — verified via git stash comparison); no new failures
    introduced by this fix

- Stop copying accessToken onto the NextAuth session object in the
  session() callback (auth.ts), since session is exposed to client-side
  JS via useSession()/getSession() and was readable via XSS (Priyanshu-byte-coder#2845)
- Add getAccessToken() helper (lib/get-session-token.ts) that reads the
  token server-side only, directly from the encrypted JWT cookie via
  next-auth/jwt's getToken()
- Migrate all API routes that previously read session.accessToken to
  use the new server-only getAccessToken() helper instead
- Update/add tests to mock getAccessToken() and verify accessToken is
  no longer present on the session object

Closes Priyanshu-byte-coder#2845
@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) type:testing GSSoC type bonus: tests (+10 pts) labels Jun 27, 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

@github-actions github-actions Bot added type:feature GSSoC type bonus: new feature type:performance GSSoC type bonus: performance (+15 pts) labels Jun 27, 2026
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:feature GSSoC type bonus: new feature type:performance GSSoC type bonus: performance (+15 pts) type:security GSSoC type bonus: security (+20 pts) type:testing GSSoC type bonus: tests (+10 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SECURITY] GitHub personal access tokens stored in plaintext browser localStorage are accessible to any JavaScript running on the page

1 participant