Skip to content

fix(auth): validate mobile OAuth redirect URI against scheme allowlist#390

Open
Ridanshi wants to merge 2 commits into
Dev-Card:mainfrom
Ridanshi:fix/oauth-mobile-redirect-validation
Open

fix(auth): validate mobile OAuth redirect URI against scheme allowlist#390
Ridanshi wants to merge 2 commits into
Dev-Card:mainfrom
Ridanshi:fix/oauth-mobile-redirect-validation

Conversation

@Ridanshi

@Ridanshi Ridanshi commented May 29, 2026

Copy link
Copy Markdown
Contributor

Closes #185

Problem

The GitHub and Google OAuth initiation endpoints accept a mobile_redirect_uri query parameter and embed it into the OAuth state without validation. During the callback flow, the value is decoded and used as the redirect destination for the user's JWT.

This allows an attacker to supply an arbitrary redirect URI and receive a victim's authentication token after a successful OAuth login flow.

Example:

/auth/github?state=mobile_x&mobile_redirect_uri=https://attacker.com/steal

In this scenario, a victim who completes authentication could be redirected to an attacker-controlled destination containing their JWT.

Root Cause

mobile_redirect_uri was accepted directly from user-controlled input and embedded into the OAuth state. The callback flow later trusted and used the decoded value without validating whether it was a legitimate mobile application redirect target.

Solution

Introduce explicit allowlist validation for mobile redirect URIs.

Allowed schemes:

  • devcard://
  • exp://

The validation is applied in two places for defense in depth:

  1. During OAuth state generation before a redirect URI is embedded.
  2. During callback processing when a redirect URI is extracted from the OAuth state.

If a supplied URI does not match the allowlist, it is ignored and the flow falls back to MOBILE_REDIRECT_URI.

Changes

  • Added isSafeMobileRedirectUri() helper.
  • Added scheme allowlist validation for mobile redirect URIs.
  • Prevented unsafe redirect URIs from being embedded into OAuth state.
  • Revalidated decoded redirect URIs before redirecting users after OAuth completion.
  • Added comprehensive unit test coverage.

Tests

Added 19 unit tests covering:

  • Allowed redirect schemes
  • Disallowed redirect schemes (http, https, javascript, malformed values)
  • OAuth state generation with valid redirect URIs
  • OAuth state generation with invalid redirect URIs
  • Redirect URI extraction from OAuth state
  • Rejection of tampered OAuth state values
  • Malformed state handling
  • Fallback behavior

All existing and new tests pass successfully.

Impact

Low risk.

The change only affects untrusted redirect URIs supplied through mobile_redirect_uri. Existing valid mobile authentication flows continue to function normally, while unsafe redirect destinations are rejected.

Security Benefit

Prevents authentication token leakage through attacker-controlled redirect destinations and ensures OAuth tokens are only delivered to trusted mobile application schemes.

@Harxhit Harxhit added the gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking. label May 30, 2026
@Ridanshi

Ridanshi commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Hi, could someone please review this PR when convenient? I've completed the implementation and tested it locally. Happy to make any required changes. Thanks!

@ShantKhatri ShantKhatri requested a review from Harxhit June 6, 2026 17:30

@Harxhit Harxhit left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please fix linting errors.

@Ridanshi Ridanshi force-pushed the fix/oauth-mobile-redirect-validation branch from 7322cca to f58b2a7 Compare June 8, 2026 16:03
@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

@Ridanshi is attempting to deploy a commit to the Prashantkumar Khatri's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

CI — Checks Failed

Backend — PASS

Check Result
Lint PASS
Test PASS
Typecheck PASS

Mobile — PASS

Check Result
Lint PASS
Test PASS

Web — FAIL

Check Result
Check FAIL
Build PASS

Last updated: Tue, 09 Jun 2026 19:30:32 GMT

@Ridanshi Ridanshi force-pushed the fix/oauth-mobile-redirect-validation branch from 66c3108 to a661f17 Compare June 8, 2026 19:51
@Harxhit

Harxhit commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

It looks like this PR still uses the previous pnpm workspace configuration. The repository has been migrated to npm workspaces, so the dependency configuration should be updated accordingly before this can be merged.

Ridanshi added 2 commits June 10, 2026 00:58
Add isSafeMobileRedirectUri() to validate the embedded redirect URI against
an explicit scheme allowlist before embedding in or extracting from OAuth
state. Resolves lint and typecheck errors in cards route and auth service.
The repository migrated from pnpm workspaces to npm in 4071cbc but
several files were not updated at that time:

- .github/pull_request_template.md: checklist items still referenced
  `pnpm -r run lint/typecheck/test`; replaced with the npm --prefix
  equivalents used by CI.
- .gitignore: removed pnpm-debug.log* (pnpm is no longer installed).
- apps/web/.gitignore: same pnpm-debug.log* removal.
- apps/mobile/jest.config.js: removed the \.pnpm/ virtual-store branch
  from the transformIgnorePatterns regex (dead code under npm).
@Ridanshi Ridanshi force-pushed the fix/oauth-mobile-redirect-validation branch from a661f17 to b307e32 Compare June 9, 2026 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved Required label for every approved PR. Gives the base +50 points and enables contribution tracking.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth state parameter is never validated, enabling login CSRF attacks

2 participants