{
  "filename": "app/continue/route.ts",
  "rule": "safeReturnTo must return a URL on the supplied origin. An external URL supplied as returnTo must fall back to the root URL on that origin.",
  "fixed": "import { NextRequest, NextResponse } from \"next/server\";\n\nfunction safeReturnTo(returnTo: string, origin: string): URL {\n  try {\n    const candidate = new URL(returnTo, origin);\n    if (candidate.origin !== origin) return new URL(\"/\", origin);\n    return candidate;\n  } catch {\n    return new URL(\"/\", origin);\n  }\n}\n\nexport function GET(request: NextRequest) {\n  const destination = safeReturnTo(request.nextUrl.searchParams.get(\"returnTo\") ?? \"/\", request.nextUrl.origin);\n  return NextResponse.redirect(destination, 303);\n}\n",
  "broken": "import { NextRequest, NextResponse } from \"next/server\";\n\nfunction safeReturnTo(returnTo: string, origin: string): URL {\n  try {\n    const candidate = new URL(returnTo, origin);\n    return candidate;\n  } catch {\n    return new URL(\"/\", origin);\n  }\n}\n\nexport function GET(request: NextRequest) {\n  const destination = safeReturnTo(request.nextUrl.searchParams.get(\"returnTo\") ?? \"/\", request.nextUrl.origin);\n  return NextResponse.redirect(destination, 303);\n}\n",
  "test": {
    "filename": "test-redirect.mjs",
    "source": "import assert from \"node:assert/strict\";\n\nconst origin = \"http://localhost:3000\";\nfor (const [input, expected] of [\n  [\"/account\", \"/account\"],\n  [\"https://example.org/\", \"/\"],\n  [\"//example.org/\", \"/\"],\n  [\"javascript:alert(1)\", \"/\"],\n]) {\n  const response = await fetch(`${origin}/continue?returnTo=${encodeURIComponent(input)}`, {redirect: \"manual\"});\n  assert.equal(response.status, 303);\n  assert.equal(response.headers.get(\"location\"), new URL(expected, origin).href);\n}\nconsole.log(\"Redirect cases passed\");\n",
    "command": "node test-redirect.mjs"
  }
}