yearn / yearn/cms

GitHub OAuth puts the access token in the URL and does not verify state server-side

Open
#160 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
0
Forks
3
Avg merge
7h 28m
Merged PRs (30d)
5

Description

Summary

The GitHub OAuth callback puts a public_repo access token in the success URL, and it exchanges code before checking state.

What happens

  1. packages/app/src/server/auth/github/callback.ts exchanges the GitHub code for an access token, then 302s to /auth/github/success?token=<access_token>&state=….
  2. packages/app/src/routes/auth/github/Success.tsx copies ?token= into sessionStorage.github_token.
  3. The server requires state to be present, but it does not compare it to a server-side/cookie-bound challenge before the token exchange. The client checks sessionStorage.auth_challenge only after the token is already in the URL.
  4. The success page then does window.location.href = sessionStorage.post_auth_redirect (default /).

Observed on cms.yearn.fi from the callback error strings and the success-page JS. I did not complete a login, so I do not have a live Location header with a real token.

Why it matters

The token can land in first-party access logs, browser history, crash reports, and any future XSS on cms.yearn.fi. That token can open PRs on yearn/cms, including vault migration.target which yearn.fi later encodes as migrate vaultTo.

This is not a remote “steal someone else’s callback 302” by itself. Post-login navigation does not forward the query, and default referrer behavior usually strips it. It is still a real credential-handling bug.

Related: Success.tsx assigns window.location.href from post_auth_redirect with no origin/path allowlist. If that value is ever //host or an absolute URL, the browser leaves cms.yearn.fi after the token is stored.

Suggested fix

  • Put the session in an HttpOnly cookie (or a one-time code the success page exchanges), never in a URL.
  • Bind state to that cookie and verify it before exchanging code.
  • Allowlist post_auth_redirect to same-origin relative paths.
  • Until that ships, send Referrer-Policy: no-referrer (and ideally nosniff + a CSP) on the success route. Production currently sends HSTS only.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/app/src/server/auth/github/callback.ts and packages/app/src/routes/auth/github/Success.tsx, tracing the callback's state validation, token handoff, and post-auth redirect. Done means the access token is not placed in a URL, state is verified before code exchange, and post_auth_redirect is restricted to same-origin relative paths.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
authentication, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.