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.
# 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.
# 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:
- CORS on your API server — restrict
Access-Control-Allow-Originto your known frontend origins - CSP on your HTML pages — restrict
script-src,connect-src,img-srcto trusted sources - 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 (
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.