← Bug of the week

Bug of the week · 2026-10-19

The redirect check that trusts a leading slash

The post-login redirect in an Express API · Security · difficulty 1/3

After a successful login, the API redirects the user back to the page they originally asked for. The target comes from a ?next= query parameter, so it is user-controlled. A teammate asked the AI assistant: "Write resolveRedirect(target, fallback) for our login endpoint. Only allow redirects to pages on our own site; anything else should go to the fallback."

The code came back with tests that pass. The contract promised by the docstring:

Keep in mind how a browser interprets a Location header: it does not only look for http://. Review the code before it ships.

No account needed. No hints. The clock is running.0 s

Click the line (or lines) where the defect is, pick its category, then submit. The code is read-only in this mode.

1/**
2 * Resolves the post-login redirect target.
3 *
4 * Returns `target` when it points to a page on this site, otherwise
5 * `fallback`. Used by the login endpoint to honour `?next=`.
6 */
7export function resolveRedirect(
8 target: string | null | undefined,
9 fallback = "/dashboard",
10): string {
11 if (!target) return fallback;
12 const trimmed = target.trim();
13 if (trimmed.length === 0) return fallback;
14 if (!isLocalPath(trimmed)) return fallback;
15 return trimmed;
16}
17
18/**
19 * True when `url` is a path on the current origin, not a link to another host.
20 */
21export function isLocalPath(url: string): boolean {
22 const lower = url.toLowerCase();
23 if (lower.startsWith("http://") || lower.startsWith("https://")) return false;
24 if (lower.includes("://")) return false;
25 return url.startsWith("/");
26}
0 lines marked