← All exercises

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");
  });
});