CORS

/kɔːrz/

n. “You may speak… but only from where I recognize you.”

CORS, short for Cross-Origin Resource Sharing, is a browser-enforced security model that controls how web pages are allowed to request resources from origins other than their own. It exists because the web learned, the hard way, that letting any site freely read responses from any other site was a catastrophically bad idea.

By default, browsers follow the same-origin policy. A script loaded from one origin — defined by scheme, host, and port — is not allowed to read responses from another. This rule prevents malicious websites from silently reading private data from places like banking portals, email providers, or internal dashboards. Without it, the browser would be an accomplice.

CORS is the controlled exception to that rule. It allows servers to explicitly declare which external origins are permitted to access their resources, and under what conditions. The browser enforces these declarations. The server does not trust the client. The client does not trust itself. The browser acts as the bouncer.

This control is expressed through HTTP response headers. When a browser makes a cross-origin request, it looks for permission signals in the response. If the headers say access is allowed, the browser hands the response to the requesting script. If not, the browser blocks it — even though the network request itself may have succeeded.

One of the most misunderstood aspects of CORS is that it is not a server-side security feature. Servers will happily send responses to anyone who asks. CORS determines whether the browser is allowed to expose that response to JavaScript. This distinction matters. CORS protects users, not servers.

Requests come in two broad flavors: simple and non-simple. Simple requests use safe HTTP methods and headers and are sent directly. Non-simple requests trigger a preflight — an automatic OPTIONS request sent by the browser to ask the server whether the real request is permitted. This preflight advertises the method and headers that will be used, and waits for approval.

The preflight mechanism exists to prevent side effects. Without it, a malicious page could trigger destructive actions on another origin using methods like PUT or DELETE without ever reading the response. CORS forces the server to opt in before the browser allows those requests to proceed.

Credentials complicate everything. Cookies, HTTP authentication, and client certificates are powerful — and dangerous. CORS requires explicit permission for credentialed requests, and forbids wildcard origins when credentials are involved. This prevents a server from accidentally granting authenticated access to the entire internet.

CORS is often confused with CSP, but they solve different problems. CSP restricts what a page is allowed to load or execute. CORS restricts what a page is allowed to read. One controls inbound behavior. The other controls outbound trust.

Many modern APIs exist entirely because of CORS. Without it, browser-based applications could not safely consume third-party services. With it, APIs can be shared selectively, documented clearly, and revoked instantly by changing headers rather than code.

CORS does not stop attackers from sending requests. It stops browsers from handing attackers the answers. In the security world, that distinction is everything.

When developers complain that CORS is “blocking their request,” what it is actually blocking is their assumption. The browser is asking a simple question: did the other side agree to this conversation? If the answer is no, the browser walks away.

CORS is not optional. It is the price of a web that allows interaction without surrendering isolation — and the reason your browser can talk to many places without betraying you to all of them.

CSP

/ˌsiː-ɛs-ˈpiː/

n. “Trust nothing by default. Especially the browser.”

CSP, short for Content Security Policy, is a defensive security mechanism built into modern browsers to reduce the damage caused by malicious or unintended content execution. It does not fix broken code. It does not sanitize input. What it does instead is draw very explicit boundaries around what a web page is allowed to load, execute, embed, or communicate with — and then enforces those boundaries with extreme prejudice.

At its core, CSP is a browser-enforced rulebook delivered by a server, usually via HTTP headers, sometimes via meta tags. That rulebook answers questions browsers used to shrug at: Where can scripts come from? Are inline scripts allowed? Can this page embed frames? Can it talk to third-party APIs? If an instruction isn’t explicitly allowed, it is blocked. Silence becomes denial.

The policy exists largely because of XSS. Cross-site scripting thrives in environments where browsers eagerly execute whatever JavaScript they encounter. For years, the web operated on a naive assumption: if the server sent it, the browser should probably run it. CSP replaces that assumption with a whitelist model. Scripts must come from approved origins. Stylesheets must come from approved origins. Inline execution becomes suspicious by default.

This matters because many real-world attacks don’t inject entire applications — they inject tiny fragments. A single inline script. A rogue image tag with an onerror handler. A compromised third-party analytics file. With CSP enabled and properly configured, those fragments simply fail to execute. The browser refuses them before your application logic ever sees the mess.

CSP is especially effective when paired with modern authentication and session handling. Even if an attacker manages to reflect or store malicious input, the policy can prevent that payload from loading external scripts, exfiltrating data, or escalating its reach. This makes CSP one of the few mitigations that still holds value when other layers have already failed.

Policies are expressed through directives. These directives describe allowed sources for different content types: scripts, styles, images, fonts, connections, frames, workers, and more. A policy might state that scripts are only allowed from the same origin, that images may load from a CDN, and that inline scripts are forbidden entirely. Browsers enforce each rule independently, creating a layered denial system rather than a single brittle gate.

Importantly, CSP can operate in reporting mode. This allows a site to observe violations without enforcing them, collecting reports about what would have been blocked. This feature turns deployment into a learning process rather than a blind leap. Teams can tune policies gradually, tightening restrictions as they understand their own dependency graph.

CSP does not replace input validation. It does not replace output encoding. It does not make unsafe frameworks safe. What it does is drastically limit the blast radius when something slips through. In that sense, it behaves more like a containment field than a shield — assuming compromise will happen, then making that compromise far less useful.

Modern frameworks and platforms increasingly assume the presence of CSP. Applications built with strict policies tend to avoid inline scripts, favor explicit imports, and document their dependencies more clearly. This side effect alone often leads to cleaner architectures and fewer accidental couplings.

CSP is not magic. Misconfigured policies can break applications. Overly permissive policies can provide a false sense of safety. But when treated as a first-class security control — alongside transport protections like TLS and authentication mechanisms — it becomes one of the most effective browser-side defenses available.

In a hostile web, CSP doesn’t ask whether content is trustworthy. It asks whether it was invited. Anything else stays outside.