Skip to content

[codex] validate magic-link redirect target#438

Merged
ralyodio merged 2 commits into
profullstack:masterfrom
lazyGPT07:codex/validate-magic-link-redirect
Jun 14, 2026
Merged

[codex] validate magic-link redirect target#438
ralyodio merged 2 commits into
profullstack:masterfrom
lazyGPT07:codex/validate-magic-link-redirect

Conversation

@lazyGPT07

Copy link
Copy Markdown
Contributor

What changed

  • resolve magic-link next values against the configured application origin
  • accept only root-relative, same-origin destinations
  • fall back to /dashboard for host-like, absolute, protocol-relative, and mixed-slash inputs
  • add focused regression tests for valid and rejected destinations

Root cause

The callback concatenated NEXT_PUBLIC_APP_URL and an unvalidated next value. A value such as @example.com formed https://ugig.net@example.com, whose effective host is example.com.

Validation

  • pre-commit lint (0 errors)
  • TypeScript type-check
  • 176 test files, 1,639 tests passed
  • production build passed

Fixes #437

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes an open-redirect vulnerability in the magic-link auth callback where an unvalidated next query parameter was concatenated directly onto the app origin, allowing an attacker to craft a confirmation link whose effective host was an external domain. A new resolveMagicLinkRedirect helper is introduced to validate and sanitize the redirect target before use.

  • Open-redirect fix: resolveMagicLinkRedirect requires next to start with /, then parses it with the WHATWG URL API using the app origin as base and rejects any result whose origin differs from the app's — catching protocol-relative paths (//), backslash-normalized paths (/\\example.com//example.com), and any absolute URL.
  • Regression tests: A new test file covers the one valid case (internal path with query string), six rejection cases (host-like, absolute, protocol-relative, bare backslash, mixed slash, empty string), and the null case.

Confidence Score: 5/5

Safe to merge — the fix correctly closes the open-redirect vulnerability with a well-tested, defence-in-depth approach.

The two-step validation (leading-slash guard followed by WHATWG URL origin comparison) handles all known redirect-bypass patterns: host-like values, absolute URLs, protocol-relative paths, backslash-normalised paths, empty strings, and null. The targeted regression suite confirms each case. No other redirect path in the file uses the user-supplied next parameter, so the blast radius is contained.

No files require special attention.

Important Files Changed

Filename Overview
src/app/auth/confirm/route.ts Introduces resolveMagicLinkRedirect with a two-step WHATWG-URL-based validation (startsWith guard + origin comparison) that correctly closes the open-redirect vector; existing redirect paths for other auth types are untouched.
src/app/auth/confirm/route.test.ts New test file with parameterised cases covering the happy path and six rejection scenarios; empty string and null are both tested, addressing the previously noted gap.

Reviews (2): Last reviewed commit: "test(auth): cover empty magic-link redir..." | Re-trigger Greptile

Comment thread src/app/auth/confirm/route.test.ts Outdated
Comment thread src/app/auth/confirm/route.test.ts
@lazyGPT07

Copy link
Copy Markdown
Contributor Author

Addressed the two test-only gaps in 60410f0: renamed the leading-backslash case to match the actual guard path and added explicit empty-string coverage. The focused redirect suite passes 8/8.

@ralyodio ralyodio merged commit c68553e into profullstack:master Jun 14, 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.

bug: magic-link confirmation accepts an external redirect target

2 participants