Security Issue: Missing OAuth State Parameter Validation
Description
The Google OAuth 2.0 login flow does not properly validate the state parameter returned by Google after authentication. The state parameter is a CSRF token that must be generated server-side, stored in session, and verified on callback. Without this check, an attacker can craft a malicious OAuth callback URL and force a victim to be logged in as the attacker's account.
Steps to Reproduce
- Initiate a Google OAuth login flow
- Observe the redirect to Google: note the
state parameter (or its absence)
- Craft a callback URL with a manipulated
state value
- Navigate to the callback URL
- Observe that the server processes the callback without rejecting the invalid state
Root Cause
The OAuth callback handler likely skips state parameter generation/validation, or checks it in a way that can be bypassed with an empty or predictable value.
Impact
- Login CSRF: attacker can trick a victim into associating their browser session with the attacker's Google account
- Account takeover in certain scenarios
- Violates OAuth 2.0 RFC 6749 Section 10.12 and OWASP A03:2021
Proposed Fix
Generate a cryptographically random state token on login initiation:
const state = crypto.randomBytes(32).toString('hex');
req.session.oauthState = state;
// Include state in the Google authorization URL
On callback, verify: if (req.query.state !== req.session.oauthState) return res.status(400).send('Invalid state');
I would like to implement this fix if assigned.
Security Issue: Missing OAuth State Parameter Validation
Description
The Google OAuth 2.0 login flow does not properly validate the
stateparameter returned by Google after authentication. Thestateparameter is a CSRF token that must be generated server-side, stored in session, and verified on callback. Without this check, an attacker can craft a malicious OAuth callback URL and force a victim to be logged in as the attacker's account.Steps to Reproduce
stateparameter (or its absence)statevalueRoot Cause
The OAuth callback handler likely skips state parameter generation/validation, or checks it in a way that can be bypassed with an empty or predictable value.
Impact
Proposed Fix
Generate a cryptographically random state token on login initiation:
On callback, verify:
if (req.query.state !== req.session.oauthState) return res.status(400).send('Invalid state');I would like to implement this fix if assigned.