Files
multica/packages/core/auth/utils.ts
Bohan Jiang 2317533da4 fix(auth): validate next= redirect target to prevent open redirect (#1309)
* refactor(auth): add sanitizeNextUrl helper in @multica/core/auth

Extracts a reusable helper that returns a post-login redirect URL only
when it's a safe single-slash relative path, and null otherwise. Rejects
absolute URLs, protocol-relative URLs, backslashes, and control
characters so call sites can safely pass the result to router.push().

Keeping the rule in a single helper (with direct unit tests) avoids
each consumer re-implementing the validation and drifting.

* fix(auth): validate next= redirect target to prevent open redirect

Closes #1116

Next.js router.push accepts absolute URLs, so a crafted
`/login?next=https://evil.example` would send the user off-origin
after a successful login. The Google OAuth callback has the same
vector via the `state=next:<url>` payload.

Sanitize both entry points through `sanitizeNextUrl` from
`@multica/core/auth` so only safe single-slash relative paths survive;
null results fall through to the existing workspace-list-based default
without any hard-coded path.

---------

Co-authored-by: JunghwanNA <70629228+shaun0927@users.noreply.github.com>
2026-04-18 13:24:01 +08:00

21 lines
830 B
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Validate a post-login redirect URL and return it only if safe to follow.
*
* Only single-slash relative paths (e.g. `/invite/abc`) are accepted. Returns
* `null` for unsafe or empty input — call sites decide the fallback so this
* helper never overloads a specific path with "user did not pass next".
*
* Rejects:
* - `null` / empty string
* - absolute URLs (`https://evil.com`, `javascript:alert(1)`, …)
* - protocol-relative URLs (`//evil.com`)
* - paths containing backslashes (Windows-style or `/\\host`)
* - paths containing ASCII control characters (`\x00``\x1f`)
*/
export function sanitizeNextUrl(raw: string | null): string | null {
if (!raw) return null;
if (!raw.startsWith("/") || raw.startsWith("//")) return null;
if (/[\x00-\x1f\\]/.test(raw)) return null;
return raw;
}