Skip to content

Bring the CORS proxy worker into the repo and harden it - #83

Open
jonocodes wants to merge 2 commits into
mainfrom
infra/cors-worker
Open

jonocodes wants to merge 2 commits into
mainfrom
infra/cors-worker

Conversation

@jonocodes

Copy link
Copy Markdown
Owner

What

Brings the Cloudflare CORS proxy worker into the repo under infra/cors-worker/ and hardens it. It previously existed only in the Cloudflare dashboard (source: dash), so it was unversioned and unreviewable. wrangler.toml keeps the same worker name, so wrangler deploy updates it in place.

Files:

  • worker.js — the worker (deployed as-is, no build step)
  • wrangler.toml — name, entry, compatibility date, observability, preview_urls = false
  • worker.test.mjs — node --test coverage
  • README.md — origin, deploy, behaviour, and scope limits

Hardening

  • Caching — the original passed the upstream Cache-Control straight through. A dead image answered 404 with cache-control: no-cache, so a retrying client re-fetched it ~24k times (the ~234k-request/day incident, Politely refetch: dedupe, negative-cache and back off repeated proxy requests #78). Now the worker overrides caching by status/content-type (images/fonts/css/js immutable for a year, HTML 5 min, 404 max-age=3600, 5xx 60s) and stores responses in caches.default.
  • SSRF guard — http(s) only; loopback/private/link-local/CGNAT/reserved addresses refused; every redirect hop re-validated.
  • Size cap — > 25 MiB → 413.
  • Log hygiene — errors only, hostname only; never the full ?url= (can contain API keys). Also removes the old per-request logging.
  • No credential passthrough — forwards only Accept/Accept-Language/Range.

There is deliberately no host allowlist — it must serve arbitrary public sites.

Testing

  • node --test infra/cors-worker/ → 10 passed (preflight, missing/invalid URL, SSRF cases, redirect-to-private, cache-header override + edge cache, immutable images, cache-hit short-circuit, size cap, secret-never-logged).
  • jest → 327 passed; tsc --noEmit and eslint clean.

Deployed

Already deployed to lively-cors-proxy-b569 (version 16cbbbd1) and verified live: preflight OK, image immutable, 127.0.0.1/169.254.169.254 → 403, missing path → 404 with cache-control: max-age=3600.

Refs #78.

The worker behind the default CORS proxy only ever existed in the
Cloudflare dashboard. Version it under infra/cors-worker/ (same worker
name, so wrangler deploys in place) with:

- cache-header overrides + edge cache, so a dead image that answers 404
  with no-cache is not re-fetched forever
- SSRF guard (http(s) only, no private/loopback/link-local, redirects
  re-validated)
- 25 MiB response cap
- error-only logging, hostname only (never the full ?url=)
- no upstream forwarding of cookies/authorization

Adds node:test coverage and declares the Workers globals for eslint.

Refs #78
@netlify

netlify Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for savrlist ready!

Name Link
🔨 Latest commit fae6ad7
🔍 Latest deploy log https://app.netlify.com/projects/savrlist/deploys/6ac3e0d37c30220008794849
😎 Deploy Preview https://deploy-preview-83--savrlist.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant