CORS Misconfiguration on Netlify
Netlify Functions (serverless APIs) and the _headers file frequently set Access-Control-Allow-Origin: * to resolve CORS errors during development. This permissive policy persists into production, allowing any website to interact with your API endpoints.
Scan Your Netlify AppHow It Happens
When a Netlify static site calls a Netlify Function on the same domain, CORS is not required (same-origin requests). But when the frontend and API are on different subdomains, or during local development where the frontend runs on localhost:3000 and Functions run on localhost:8888, CORS errors appear. Developers fix this by adding Access-Control-Allow-Origin: * to their Netlify Function responses. The error goes away, the app works, and the wildcard CORS policy ships to production unchanged. Another common pattern is using the _headers file to set CORS headers on all paths (/*), which makes every static asset and Function endpoint accept cross-origin requests. This blanket approach is especially dangerous for Netlify Functions that handle authenticated requests.
Impact
Permissive CORS on Netlify Functions that handle user data allows any website to make requests to your API. If the Function uses cookies or reads an Authorization header, a malicious site visited by your user can steal their data by calling your API cross-origin. For Netlify sites that use identity and access tokens, CORS misconfiguration enables cross-site data theft without needing any vulnerability in your own code. The attacker simply creates a page that makes fetch requests to your Netlify Functions. Netlify Functions that mutate data (create, update, delete operations) are also at risk. An attacker can create a page that submits forms or sends POST requests to your Functions, performing actions as the visiting user.
How to Detect
Test your Netlify Functions with a foreign Origin header: curl -H "Origin: https://evil.com" -I https://your-site.netlify.app/.netlify/functions/api. If the response includes Access-Control-Allow-Origin: * or reflects the evil.com origin, CORS is misconfigured. Check your _headers file for Access-Control-Allow-Origin headers applied to broad paths. Check each Netlify Function for CORS header settings in the response object. Vibe App Scanner tests CORS configuration on all detected API endpoints, including Netlify Functions, and flags overly permissive origin policies.
How to Fix
Set Access-Control-Allow-Origin to your specific site domain in Netlify Functions. If your site is https://example.com, only allow that origin. For multiple legitimate origins, validate against an allowlist and reflect only matching origins. Remove blanket CORS headers from the _headers file. If CORS is needed, apply it only to specific API paths (/.netlify/functions/*) with specific origins, not to all paths. Use Netlify's same-origin advantage: when your static site and Functions are on the same domain, CORS is not needed at all. Configure Netlify rewrites in netlify.toml to proxy Function calls through a same-origin path. For Functions that accept credentials, never use Access-Control-Allow-Origin: *. Specify the exact origin and set Access-Control-Allow-Credentials: true only when required.
Code Examples
CORS in a Netlify Function
// Netlify Function with wildcard CORS
export async function handler(event) {
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
},
body: JSON.stringify(userData),
}
}const ALLOWED_ORIGINS = [
'https://example.com',
'https://staging.example.com',
]
export async function handler(event) {
const origin = event.headers.origin || ''
const corsOrigin = ALLOWED_ORIGINS.includes(origin)
? origin : ALLOWED_ORIGINS[0]
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': corsOrigin,
'Access-Control-Allow-Credentials': 'true',
},
body: JSON.stringify(userData),
}
}Frequently Asked Questions
Do I need CORS if my frontend and Functions are on the same Netlify domain?
No. If your static site and Netlify Functions are served from the same domain (e.g., example.com), browser same-origin policy allows the requests without CORS. Use Netlify rewrites to proxy Function calls through a same-origin path.
Why is Access-Control-Allow-Origin: * with credentials dangerous?
This combination tells the browser to send cookies with cross-origin requests and accept responses from any origin. Browsers block the literal combination, so developers reflect the request Origin instead, which is equally dangerous and not blocked by browsers.
Can I use Netlify redirects instead of CORS?
Yes. Configure a redirect in netlify.toml like [[redirects]] from = "/api/*" to = "/.netlify/functions/:splat" status = 200. This proxies requests through the same origin, eliminating the need for CORS entirely.
Related Security Resources
Is Your App Vulnerable?
VAS automatically scans for cors misconfiguration and other security issues in Netlify apps. Get actionable results with step-by-step fixes.
Scans from $5, results in minutes.