trails/apps/planner/app/routes
Ullrich Schäfer 51e6b8a0d7
fix(planner): validate callback/returnUrl + cap session URL-param payloads
Addresses planner audit #3 (SSRF via callbackUrl) and #7 (URL-param
size). Two attack surfaces hardened:

1. /new loader — \`callback\`, \`token\`, \`returnUrl\`, \`gpx\` query
   params now validated:
   - callbackUrl: must be a valid absolute http(s) URL ≤ 2048 chars.
     If \`PLANNER_CALLBACK_ALLOWED_HOSTS\` is set (comma-separated),
     the host must match — defense-in-depth SSRF guard for self-
     hosted instances. Unset = no allowlist (dev / open self-host).
   - token: max 2048 chars.
   - returnUrl: must be a same-origin path or absolute http(s) URL
     ≤ 2048 chars. Rejects \`javascript:\`, \`data:\`, and
     protocol-relative \`//host\` (which would resolve to a remote
     origin on HTTPS pages).
   - gpx: ≤ 2 MB encoded.
   Invalid input throws 400 from the loader.

2. /session/:id default-export component — \`waypoints\`, \`noGoAreas\`,
   \`notes\`, \`returnUrl\` URL params now bounded before
   \`JSON.parse\` / use:
   - waypoints / noGoAreas: ≤ 50KB each; over-cap returns undefined
     (component starts with empty initial state, same as malformed).
   - notes: ≤ 10KB.
   - returnUrl: ≤ 2KB + same scheme rules as #1.

Pulled the URL validation into \`lib/url-validation.server.ts\` so
both routes (and any future caller) share the same rules.

Tests: \`url-validation.server.test.ts\` (14 cases — schemes,
allowlist, length caps, protocol-relative guards, env parsing).

Full repo: pnpm typecheck / lint / test all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 00:05:47 +02:00
..
api.overpass.test.ts Fix planner build: move Overpass upstream fetch to overpass.server.ts 2026-04-23 22:40:15 +02:00
api.overpass.ts Fix planner build: move Overpass upstream fetch to overpass.server.ts 2026-04-23 22:40:15 +02:00
api.route-segments.ts Cache BRouter segments client-side, fetch only the diff 2026-04-24 17:57:54 +02:00
api.route.ts Session-bind /api/route and /api/overpass 2026-04-21 22:18:45 +02:00
api.sessions.ts Centralize waypoint Yjs serialization in waypointFromYMap/waypointToYMap 2026-05-18 21:02:27 +02:00
home.tsx Add legal pages, ToS acceptance, and alpha banner 2026-04-18 00:08:48 +02:00
new.tsx fix(planner): validate callback/returnUrl + cap session URL-param payloads 2026-05-26 00:05:47 +02:00
session.$id.tsx fix(planner): validate callback/returnUrl + cap session URL-param payloads 2026-05-26 00:05:47 +02:00