The redirect check that trusts a leading slash
The post-login redirect in an Express API · difficulty 1/3 · ~5 min
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:
- `resolveRedirect(target, fallback)` returns `target` when it is a local path on this site, and `fallback` otherwise.
- A missing, empty or whitespace-only `target` falls back.
- Absolute URLs to other hosts (`https://evil.example`) must never be returned.
- `isLocalPath(url)` is the predicate behind it: `true` only for paths that the browser will resolve on the current origin.
Keep in mind how a browser interprets a `Location` header: it does not only look for `http://`. Review the code before it ships.
code.ts
Visible tests (they pass on the code as given)
import { describe, it, expect } from "@debunk/harness";
import { resolveRedirect, isLocalPath } from "./code";
describe("resolveRedirect", () => {
it("keeps a local path", () => {
expect(resolveRedirect("/settings/profile?tab=security")).toBe("/settings/profile?tab=security");
});
it("falls back for an absolute URL to another host", () => {
expect(resolveRedirect("https://evil.example/login")).toBe("/dashboard");
expect(isLocalPath("http://evil.example")).toBe(false);
});
it("falls back when the target is missing", () => {
expect(resolveRedirect(null)).toBe("/dashboard");
expect(resolveRedirect(" ", "/home")).toBe("/home");
});
});