All Docs
FeaturesCalmony Sanctions MonitorUpdated March 12, 2026

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:

  1. Validates the Origin request header against a server-side allowlist of permitted external domains.
  2. Sets Access-Control-Allow-Origin to the matched origin (never a wildcard *) when the origin is on the allowlist.
  3. Handles preflight OPTIONS requests by returning the appropriate Access-Control-Allow-Methods and Access-Control-Allow-Headers headers.
  4. 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-Origin entirely (browser same-origin policy applies), or
  • Setting Access-Control-Allow-Origin to 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 typeBefore v0.1.109After v0.1.109
Same-origin (browser, dashboard)Works (browser default)Works (explicit policy)
Allowlisted external domainWorks by accident (no check)Works (explicit allow)
Unlisted external domainWorks by accident (no check)Blocked (no CORS header)
Server-to-server (no browser)UnaffectedUnaffected

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.