# CORS vs CSP

> Understand the difference between CORS and Content Security Policy. Both are browser security mechanisms but they protect against completely different threats.

Source: https://howhttpworks.com/compare/cors-vs-csp
Last reviewed: 2026-10-04

> **TL;DR:** CORS controls which origins can read your API responses (protects your server from unauthorized cross-origin reads). CSP controls which resources your page can load (protects your users from injected malicious content).

## The Core Difference

CORS and CSP are both browser security mechanisms enforced via HTTP headers, but they protect against entirely different threats:

**CORS (Cross-Origin Resource Sharing)** controls which origins can read responses from your server. It protects your API and data from being accessed by unauthorized websites.

**CSP (Content Security Policy)** controls which resources your page is allowed to load and execute. It protects your users from malicious content injected into your page (XSS attacks).

Think of it this way: CORS is about who can talk to your server. CSP is about what your page is allowed to do.

## Threat Model Comparison

| | CORS | CSP |
|---|---|---|
| Protects against | Unauthorized cross-origin reads | XSS / content injection |
| Who is protected | Your server / API | Your users |
| Enforced by | Browser (on responses) | Browser (on page loads) |
| Configured on | The server being called | The page serving the HTML |
| Header direction | Response header from API | Response header from page |

## How CORS Works

When a browser makes a cross-origin request (e.g., `app.example.com` fetching from `api.example.com`), it checks the response for `Access-Control-Allow-Origin`. If the header is absent or doesn't match the requesting origin, the browser blocks the JavaScript from reading the response.

The request still reaches the server — CORS is not a firewall. It only controls whether the browser exposes the response to the requesting page's JavaScript.

```http
# Allow a specific origin to read responses
Access-Control-Allow-Origin: https://app.example.com

# Allow any origin (public APIs only)
Access-Control-Allow-Origin: *
```

## How CSP Works

CSP is a header sent with your HTML page that tells the browser which sources are trusted for scripts, styles, images, fonts, and other resources.

```http
# Only load scripts from same origin and a trusted CDN
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
```

If an attacker injects `<script src="https://evil.com/steal.js">` into your page via XSS, CSP blocks it from loading because `evil.com` is not in the allowlist.

## Common Confusion

**"I set CORS headers, so my site is secure"** — CORS does nothing to prevent XSS. An attacker who injects a script into your page runs in your origin and bypasses CORS entirely (same-origin requests are never blocked by CORS).

**"CSP will block my CORS requests"** — CSP's `connect-src` directive controls which URLs JavaScript can fetch. If your CSP doesn't include your API origin in `connect-src`, the fetch will be blocked by CSP before CORS even applies.

**"CORS prevents CSRF"** — CORS does not prevent CSRF. Simple requests (forms, images) are not subject to CORS preflight. Use `SameSite=Strict` or `SameSite=Lax` cookies and CSRF tokens for CSRF protection.

## Using Both Together

A well-secured application uses both:

1. **CORS** on your API server — restrict `Access-Control-Allow-Origin` to your known frontend origins
2. **CSP** on your HTML pages — restrict `script-src`, `connect-src`, `img-src` to trusted sources
3. **SameSite cookies** — complement both by preventing cross-site cookie sending

Neither replaces the other. They operate at different layers and address different attack vectors.

## FAQ

### Do I need both CORS and CSP?

Yes, they solve different problems. CORS protects your API from being read by unauthorized origins — it is server-side protection for your data. CSP protects your users from malicious scripts injected into your page — it is client-side protection against XSS. A site can have perfect CORS configuration and still be vulnerable to XSS, and vice versa.

### Does CORS prevent CSRF attacks?

No. CORS controls whether a cross-origin page can read the response, but it does not prevent the request from being sent. A CSRF attack sends a forged request — the attacker does not need to read the response. Use CSRF tokens or SameSite cookies to prevent CSRF. CORS is not a CSRF defense.

### What does Access-Control-Allow-Origin: * actually allow?

It allows any origin to read the response body. It does not allow cookies or Authorization headers to be sent — those require Access-Control-Allow-Credentials: true and a specific (non-wildcard) origin. Using * is safe for public APIs that return non-sensitive data, but never combine * with credentials.

### What is a CSP nonce and when should I use it?

A nonce is a random value included in the CSP header (script-src: nonce-abc123) and in the script tag (<script nonce="abc123">). Only scripts with the matching nonce execute. Use nonces when you have inline scripts that you control but cannot move to external files. Nonces must be regenerated on every request — a static nonce provides no security.

### Why does my CORS preflight return 200 but the actual request still fails?

The preflight (OPTIONS) and the actual request are checked separately. A 200 preflight means the server accepted the OPTIONS request, but the actual request may still fail if the response is missing Access-Control-Allow-Origin, or if the origin does not match, or if credentials are involved and Access-Control-Allow-Credentials is not set. Check the actual request response headers, not just the preflight.

## References

- [MDN Web Docs: Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
- [MDN Web Docs: Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
- [OWASP: Content Security Policy Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html)
