Skip to content

fix(security): bind link-github OAuth state to authenticated session#342

Merged
Priyanshu-byte-coder merged 1 commit into
Priyanshu-byte-coder:mainfrom
anshul23102:fix/link-github-csrf-state-session-binding
May 19, 2026
Merged

fix(security): bind link-github OAuth state to authenticated session#342
Priyanshu-byte-coder merged 1 commit into
Priyanshu-byte-coder:mainfrom
anshul23102:fix/link-github-csrf-state-session-binding

Conversation

@anshul23102
Copy link
Copy Markdown
Contributor

Closes #341

What was wrong

The OAuth `state` in `/api/auth/link-github` was a random nonce with no binding to the authenticated user's session. An attacker who places their state cookie on a victim's browser can redirect the victim to the callback URL with the attacker's OAuth code. The callback passes the cookie/state match check and links the attacker's secondary GitHub account to the victim's devtrack profile under the victim's session.

What changed

`src/app/api/auth/link-github/route.ts`

  • State is now `.<session.githubId>` instead of just a random nonce
  • The session user's GitHub ID is embedded so the callback can verify it

`src/app/api/auth/link-github/callback/route.ts`

  • After the existing cookie/state match check, extracts the embedded githubId from the state
  • Verifies the embedded ID equals `session.githubId`
  • Rejects with `invalid_state` if they differ — a state generated for user A cannot complete the flow under user B's session

Why this is safe

GitHub IDs are numeric integers and will never contain a `.`, so the `.` format parses unambiguously. The 32-byte random nonce prefix still prevents brute-force state guessing.

Files changed

  • `src/app/api/auth/link-github/route.ts`
  • `src/app/api/auth/link-github/callback/route.ts`

Type of change

  • Security fix
  • Bug fix

The OAuth state generated by /api/auth/link-github was a random nonce
with no binding to the authenticated user's session. An attacker who
places their state cookie on a victim's browser (via XSS, cookie tossing,
or a shared device) could redirect the victim to the callback URL with
the attacker's OAuth code and state. The callback would pass the
cookie/state match check, then link the attacker's secondary GitHub
account to the victim's devtrack profile under the victim's session.

Fix: embed session.githubId into the state as <nonce>.<githubId>.
The callback now extracts the embedded ID after the cookie/state match
and verifies it equals session.githubId. A state generated for user A
is therefore rejected when the callback runs under user B's session,
regardless of whether the cookie and URL param match.

Files changed:
- src/app/api/auth/link-github/route.ts: state now includes githubId
- src/app/api/auth/link-github/callback/route.ts: verifies embedded ID
@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

@anshul23102 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.

@Priyanshu-byte-coder Priyanshu-byte-coder marked this pull request as ready for review May 19, 2026 05:14
@Priyanshu-byte-coder Priyanshu-byte-coder self-requested a review as a code owner May 19, 2026 05:14
Copy link
Copy Markdown
Owner

@Priyanshu-byte-coder Priyanshu-byte-coder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid CSRF mitigation. Embedding githubId in the state nonce and verifying it in the callback prevents cookie-tossing attacks — an attacker's state cookie placed on a victim's browser will fail the ID check. The nonce still provides randomness so state can't be predicted. Correct.

@Priyanshu-byte-coder Priyanshu-byte-coder merged commit ee47873 into Priyanshu-byte-coder:main May 19, 2026
7 checks passed
@Priyanshu-byte-coder Priyanshu-byte-coder added gssoc:approved GSSoC: PR approved for scoring level:advanced GSSoC: Advanced difficulty (55 pts) gssoc26 GSSoC 2026 contribution type:security GSSoC type bonus: security (+20 pts) quality:exceptional GSSoC: Exceptional quality multiplier (×1.5) labels May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved GSSoC: PR approved for scoring gssoc26 GSSoC 2026 contribution level:advanced GSSoC: Advanced difficulty (55 pts) quality:exceptional GSSoC: Exceptional quality multiplier (×1.5) type:security GSSoC type bonus: security (+20 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] link-github OAuth state not bound to session — attacker can link their GitHub account to another user's profile

2 participants