Security Deep-Dive: Hardening CORS on the REST API (SEC-13)
Security Deep-Dive: Hardening CORS on the REST API (SEC-13)
Release: v0.1.109 | Control: SEC-13 | Category: Infrastructure Security
Background
Cross-Origin Resource Sharing (CORS) is the mechanism by which a browser decides whether a web page loaded from one origin is permitted to make HTTP requests to a different origin. Without explicit CORS headers in API responses, browsers fall back to the same-origin policy — which is safe by default, but implicit.
Before v0.1.109, no Access-Control-Allow-Origin headers were set on any route handler in this platform, including the externally-facing /api/v1/* REST endpoints. This meant:
- Cross-origin behaviour depended entirely on browser defaults rather than deliberate server-side policy.
- Any future infrastructure or configuration change could inadvertently expose the API to unintended cross-origin callers without a clear policy to enforce against.
- There was no distinction in cross-origin posture between public REST API routes and private internal routes.
What Changed
/api/v1/* — External REST API Routes
An explicit CORS middleware has been added to all REST API v1 routes. The middleware:
- Validates the
Originrequest header against a server-side allowlist of permitted external domains. - Sets
Access-Control-Allow-Originto the matched origin (never a wildcard*) when the origin is on the allowlist. - Handles preflight
OPTIONSrequests by returning the appropriateAccess-Control-Allow-MethodsandAccess-Control-Allow-Headersheaders. - Rejects requests from unlisted origins by omitting the CORS headers entirely, causing the browser to block the response.
Internal API Routes
All internal API routes (outside /api/v1/*) now explicitly deny cross-origin access by either:
- Omitting
Access-Control-Allow-Originentirely (browser same-origin policy applies), or - Setting
Access-Control-Allow-Originto the application's own domain where a response header is required.
This ensures the internal surface area is hardened regardless of future configuration drift.
Impact on Integrations
| Consumer type | Before v0.1.109 | After v0.1.109 |
|---|---|---|
| Same-origin (browser, dashboard) | Works (browser default) | Works (explicit policy) |
| Allowlisted external domain | Works by accident (no check) | Works (explicit allow) |
| Unlisted external domain | Works by accident (no check) | Blocked (no CORS header) |
| Server-to-server (no browser) | Unaffected | Unaffected |
Note: CORS is a browser-enforced mechanism. Server-to-server API calls (e.g. from a backend integration, a CI pipeline, or a server-side SDK) are not subject to CORS restrictions and are unaffected by this change.
Action Required for External Integrations
If you operate a browser-based application that calls the /api/v1/* endpoints cross-origin, your domain must be included in the configured CORS allowlist.
Contact your platform administrator or refer to your deployment configuration to add your domain. Requests from domains not on the allowlist will receive no CORS headers and will be blocked by the browser.
Security Rationale
This change moves the platform from an implicit to an explicit security posture for cross-origin access. The principle applied is:
Default deny. Explicitly permit only what is necessary.
This is consistent with the broader approach to API security on this platform and reduces the risk of unintended cross-origin data exposure if configuration changes are made in future.