Skip to content

fix(api): validate OAuth redirect + require non-empty state#24

Merged
ralyodio merged 1 commit into
profullstack:mainfrom
AliaksandrNazaruk:fix/oauth-open-redirect-and-state
Jul 2, 2026
Merged

fix(api): validate OAuth redirect + require non-empty state#24
ralyodio merged 1 commit into
profullstack:mainfrom
AliaksandrNazaruk:fix/oauth-open-redirect-and-state

Conversation

@AliaksandrNazaruk

Copy link
Copy Markdown
Contributor

Problem

Two bugs in the CoinPay OAuth flow (services/api/src/index.ts), see #23:

  1. Open redirect / session-token leak (HIGH): the redirect query param was stored and, after login, the session token was appended to it and the browser redirected there — unvalidated. ?redirect=https://evil.com leaks the victim's session token.
  2. State check bypass (login CSRF): state !== cookie passes when both are undefined (missing cookie + missing state param).

Fix

  • safeRedirect() (new redirect.ts) — only same-origin absolute URLs or site-relative paths are honored; external / protocol-relative / javascript: / cross-scheme fall back to the default.
  • Require a non-empty state matching the cookie.

Tests

redirect.test.ts (same-origin allowed; external, //evil.com, javascript:, cross-scheme, empty all rejected). Verified standalone.

Fixes #23.

…leak / login CSRF)

Two bugs in the CoinPay OAuth flow (services/api/src/index.ts):

1. Open redirect / session-token exfiltration (HIGH). The 'redirect' query
   param was stored and, after login, the fresh session token was appended to
   it (`${redirect}#token=${sess}`) and the browser redirected there — with
   no validation. ?redirect=https://evil.com leaks the victim's session token
   to an attacker host. Add safeRedirect() (new redirect.ts) that only honors
   same-origin absolute URLs or site-relative paths; everything else falls back
   to the safe default.

2. OAuth state CSRF (MEDIUM). The callback checked `state !== cookie`, but a
   missing cookie AND missing state param both read as undefined, so
   `undefined !== undefined` is false and the check was bypassed. Require a
   non-empty state that matches the cookie.

Adds redirect.test.ts (same-origin allowed; external / protocol-relative /
javascript: / cross-scheme rejected). Logic verified standalone.
@ralyodio ralyodio merged commit cfaf461 into profullstack:main Jul 2, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth: open redirect leaks session token + bypassable state check (login CSRF)

2 participants