In apps/backend/src/routes/auth.ts, the state query parameter is generated during the OAuth redirect but never verified in the callback handlers. The callback simply ignores state:
app.get('/github/callback', async (request, reply) => {
const { code } = request.query; // state is never read or checked
...
});
This makes the CSRF protection completely non-functional. An attacker can initiate a forged OAuth flow and the server will accept it regardless of state.
Expected behaviour
The callback should verify that the state returned by GitHub/Google matches the one sent in the original redirect. Typically this is stored server-side (Redis) or in a signed cookie before the redirect.
Proposed fix
Store the generated state in a short-lived signed cookie before redirecting, then verify it matches in the callback before processing the token exchange.
Files to touch
apps/backend/src/routes/auth.ts
ASSIGNMENT REQUEST — add this at the very bottom of the issue body:
I would like to work on this issue as part of GirlScript Summer of Code 2026 (GSSoC'26). I have reviewed the codebase and understand the root cause and the fix required.
Could you please assign this issue to me?
GitHub: @MehtabSandhu11
Thank you!
In
apps/backend/src/routes/auth.ts, thestatequery parameter is generated during the OAuth redirect but never verified in the callback handlers. The callback simply ignoresstate:This makes the CSRF protection completely non-functional. An attacker can initiate a forged OAuth flow and the server will accept it regardless of state.
Expected behaviour
The callback should verify that the
statereturned by GitHub/Google matches the one sent in the original redirect. Typically this is stored server-side (Redis) or in a signed cookie before the redirect.Proposed fix
Store the generated state in a short-lived signed cookie before redirecting, then verify it matches in the callback before processing the token exchange.
Files to touch
apps/backend/src/routes/auth.tsASSIGNMENT REQUEST — add this at the very bottom of the issue body:
I would like to work on this issue as part of GirlScript Summer of Code 2026 (GSSoC'26). I have reviewed the codebase and understand the root cause and the fix required.
Could you please assign this issue to me?
GitHub: @MehtabSandhu11
Thank you!