Scope CORS to browser routes only, fail closed on CORS_ORIGIN #4

Merged
matt merged 4 commits from mailship-32x-cors-is-not-production-safe-wildcard-ori-52b into main 2026-09-10 19:46:02 +00:00
Collaborator

mailship-32x

The server was setting Access-Control-Allow-Origin: * on every route via process.env.CORS_ORIGIN ?? '*', including the unauthenticated GET /subscription/email?pubkey=... which returns the subscriber's email address. Any website could query known pubkeys and harvest emails.

Changes:

  • src/env.ts — CORS_ORIGIN is now a required env var (fail closed). The server refuses to start without it. Also exported for use in server middleware.
  • src/server.ts — replaced the blanket CORS middleware with a scoped corsMiddleware that skips server-to-server routes (/notify), reads CORS_ORIGIN from env (no ?? '*' fallback), and adds Vary: Origin.
  • .env.template — documented the new required variable.
  • test/cors.test.sh — integration test that verifies: configured origin on browser routes, Vary: Origin presence, no CORS headers on /notify, and correct preflight responses.

How to test: Set CORS_ORIGIN=https://your-app.com in the environment (or .env). Without it, the server will exit with Error: CORS_ORIGIN is not defined. Run bash test/cors.test.sh for automated verification.

mailship-32x The server was setting `Access-Control-Allow-Origin: *` on every route via `process.env.CORS_ORIGIN ?? '*'`, including the unauthenticated `GET /subscription/email?pubkey=...` which returns the subscriber's email address. Any website could query known pubkeys and harvest emails. **Changes:** - `src/env.ts` — `CORS_ORIGIN` is now a required env var (fail closed). The server refuses to start without it. Also exported for use in server middleware. - `src/server.ts` — replaced the blanket CORS middleware with a scoped `corsMiddleware` that skips server-to-server routes (`/notify`), reads `CORS_ORIGIN` from env (no `?? '*'` fallback), and adds `Vary: Origin`. - `.env.template` — documented the new required variable. - `test/cors.test.sh` — integration test that verifies: configured origin on browser routes, `Vary: Origin` presence, no CORS headers on `/notify`, and correct preflight responses. **How to test:** Set `CORS_ORIGIN=https://your-app.com` in the environment (or `.env`). Without it, the server will exit with `Error: CORS_ORIGIN is not defined.` Run `bash test/cors.test.sh` for automated verification.
hudson added 4 commits 2026-09-10 16:27:03 +00:00
The server was setting Access-Control-Allow-Origin: * on every route,
including the unauthenticated GET /subscription/email which returns the
subscriber's email address. Any website could query known pubkeys and
harvest emails.

Changes:
- src/env.ts: require CORS_ORIGIN env var (fail closed, no wildcard)
- src/server.ts: scope CORS middleware to browser-facing routes only,
  skip /notify (server-to-server), add Vary: Origin header, import
  CORS_ORIGIN from env instead of defaulting to '*'
- .env.template: document new CORS_ORIGIN variable
- test/cors.test.sh: verify CORS on browser routes, no CORS on
  server-to-server routes, Vary: Origin presence
eslint flagged netContext as imported but never used (pre-existing).
Removing the unused import so the repo's eslint gate passes on the
modified area.
matt approved these changes 2026-09-10 19:45:57 +00:00
matt merged commit 8837d3fadd into main 2026-09-10 19:46:02 +00:00
matt deleted branch mailship-32x-cors-is-not-production-safe-wildcard-ori-52b 2026-09-10 19:46:14 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: matt/mailship#4
No description provided.