Skip to content

fix(security): stop exposing GitHub access token on client-visible session (#2845) - #3132

Closed
BCA-krishna wants to merge 2 commits into
Priyanshu-byte-coder:mainfrom
BCA-krishna:fix/issue-2845-core-auth
Closed

BCA-krishna wants to merge 2 commits into
Priyanshu-byte-coder:mainfrom
BCA-krishna:fix/issue-2845-core-auth

Conversation

@BCA-krishna

Copy link
Copy Markdown
Contributor

Closes #2845

What changed and why

The NextAuth session() callback in src/lib/auth.ts was copying the
raw GitHub OAuth access token onto the session object. Since session
is returned to the browser via useSession()/getSession(), any
JavaScript on the page — including an XSS payload — could read the token
and gain full GitHub API access with the granted scopes.

Files changed (3 files only)

  • src/lib/auth.ts — removed session.accessToken = token.accessToken
    from the session() callback. Token stays in the encrypted HttpOnly
    JWT cookie only.
  • src/lib/get-session-token.ts — added getAccessToken(), a
    server-only helper that reads the token directly from the JWT via
    next-auth/jwt's getToken(), for use in API route handlers.
  • test/auth.test.ts — updated test to assert that accessToken is
    NOT present on the session object (previously asserted the opposite).

Follow-up

API routes that currently read session.accessToken will be migrated to
getAccessToken() in a follow-up PR. Those routes are all server-side
(src/app/api/) and never reach the browser, so they continue to work
correctly via the session callback until migrated.

Testing

  • npm run type-check — 0 errors
  • npm run lint — 0 errors
  • npm test — auth.ts tests all pass (18/18)

…ssion

The NextAuth session() callback was copying the GitHub OAuth access token
onto the session object, which is returned to the browser via
useSession()/getSession(). Any JavaScript running on the page —
including a successful XSS payload — could read it directly.

Changes:
- Remove session.accessToken assignment from the session() callback in
  src/lib/auth.ts; the token now stays only in the encrypted HttpOnly
  JWT cookie that NextAuth manages and never reaches the browser.
- Add getAccessToken() to src/lib/get-session-token.ts: a server-only
  helper that reads the token directly from the JWT via next-auth/jwt
  getToken(), for use in API route handlers.
- Update test/auth.test.ts to assert that accessToken is NOT present on
  the session object (was asserting the opposite before this fix).

API routes that still read session.accessToken will be migrated to
getAccessToken() in a follow-up PR to keep this change reviewable.

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 Jul 4, 2026
@github-actions

github-actions Bot commented Jul 4, 2026

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 Jul 4, 2026
@BCA-krishna

Copy link
Copy Markdown
Contributor Author

Hi @Priyanshu-byte-coder , please review this PR.
thanks.

@Priyanshu-byte-coder

Copy link
Copy Markdown
Owner

Same author, minimal version of #2875 — but removing session.accessToken on its own can't work: 39 API routes still read session.accessToken, so this branch red-lights the Playwright smoke tests (all those routes lose their token). The full migration in #2875 is the way to land this. Closing here in favor of getting #2875 fixed up (it has a Next 16 async headers()/cookies() bug to sort out first — details on that PR). Let's consolidate the effort there.

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

2 participants