Creative ideas + design notes
Commits with substantial prose (≥120 chars) — the rationale behind each move.
7a4c7ef · 2026-05-19 · add LEDGER NOTE flagging permissive CORS for follow-up
SSRF was the prioritized hardening; CORS origin:"*" is intentionally
left in place because the only known client (public/index.html) is
same-origin and tightening to a guessed allowlist could break an
undocumented embed. Note records the trade-off + recommends a
CORS_ALLOWED_ORIGINS env-var as the next step.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0a1b751 · 2026-05-19 · wire 'npm test' to the SSRF test suite
Makes the guard tests discoverable via the standard npm-script path so
future audits / CI can run them without spelunking for the file.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5c4df7c · 2026-05-19 · add test/ssrf.test.js — 25 SSRF guard cases, zero deps
Covers the 4 required cases (file:// → 400, http://localhost/ → 403,
http://169.254.169.254/ → 403, https://example.com/ resolves), plus
IPv6 loopback, IPv4-mapped-loopback, gopher/javascript/ftp/data
scheme rejection, every IPv4 private CIDR (RFC1918 + CGNAT + link-local
+ multicast + boundary), redirect-target re-validation, and malformed
URL handling. No mocha/jest/chai — pure node + console PASS/FAIL,
process exits non-zero on any failure. Run via: node test/ssrf.test.js
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
21bf7c6 · 2026-05-19 · route /api/fetch + Socket.IO load-url through safeFetch()
Replaces the direct axios.get(userUrl) call in fetchWebContent() with
lib/safe-fetch.js. Both POST /api/fetch and io.on('load-url') now share
the same hardened path — no bypass. The API layer translates
err.statusCode (400 / 403 / 502) onto the HTTP response so clients see
the right code instead of a blanket 500.
Closes SSRF surface area at server.js:32-101 + :114-129 (file://,
http://127.0.0.1:9xxx pm2 dashboards, 169.254.169.254 cloud metadata,
localhost:5432 Postgres, etc.).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f15b9a4 · 2026-05-19 · add lib/safe-fetch.js — SSRF-hardened wrapper around axios
Enforces scheme allowlist (http/https only), DNS-resolves the hostname
and rejects any private/internal/link-local/loopback/CGNAT/multicast/
IPv6-ULA target, pins the resolved IP into the axios request to defeat
DNS rebinding, follows redirects manually (max 5 hops, re-validates each
Location), and caps response size at 5 MB with a 10 s timeout. Errors
carry .statusCode and .isSsrfBlock for the API layer to translate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83bda2d · 2026-05-19 · fix .gitignore: expand broken literal "\n" line + dedupe + add snapshot patterns
Line 1 was a single 39-char string containing literal backslash-n sequences
("node_modules/\n.next/\n…") that never got expanded — ignored nothing real.
Replaced with proper newline-separated entries, deduped node_modules / .env*
/ *.log / dist / .next blocks, added snapshot-file patterns to match the new
404-guard middleware.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3be3c67 · 2026-05-19 · add 404-guard middleware for snapshot/editor file patterns before express.static
Defense-in-depth per fleet-refactor-sweep standing rule — blocks *.bak, *.orig,
*.rej, *.swp, *.pre-*, *~ even if such a file accidentally lands in public/.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>