TL;DR
- Cursor and Claude Code default to
cors()with no arguments -- any website can read your API responses - CWE-942 affects Express, Fastify, and FastAPI backends generated without explicit origin config
- Fix: pass an explicit origin array and set
credentials: true; browsers enforce the restriction for you
I reviewed four side projects last week, all vibe-coded with Cursor. Clean structure, decent test coverage, working auth flows. Then I checked the CORS configuration in each one.
Every single one had this:
app.use(cors()); // CWE-942: wildcard CORS origin
No origin list. No credentials config. Zero arguments. That defaults to Access-Control-Allow-Origin: * -- any website can read your API responses. Build a page at evil.com that fires a fetch to your endpoint, and the browser returns the full response.
One of those projects had user profile endpoints. Another had an /api/admin/users route with no rate limiting. Both were behind open CORS. Neither developer knew it.
The Vulnerable Pattern (CWE-942)
Here is what Cursor generates when you ask it to "add CORS support to this Express server":
const cors = require('cors');
app.use(cors()); // Access-Control-Allow-Origin: *
FastAPI gets the same treatment:
app.add_middleware(CORSMiddleware, allow_origins=["*"])
No options means wildcard. The cors package defaults to permissive because it works out of the box for local dev. AI editors reproduce this pattern because it shows up in training data far more often than the restricted version.
Why This Pattern Keeps Appearing
The cors documentation opens with:
// Enable All CORS Requests
app.use(cors())
That exact line is in the official README. It is in every StackOverflow answer from 2015. Every beginner tutorial. The wildcard default exists because debugging CORS locally is painful, and the docs assume you will read the next section about restricting it in production.
AI editors see thousands of examples of cors() with no args for every one with an explicit origin whitelist. That is what they generate. They have no concept of "this code is for production vs local dev" unless you spell it out in the prompt. Ask Cursor to "add CORS for a production Express server" and you get a much better answer. Ask for "add CORS" and you get the tutorial.
The Fix
Replace the wildcard with an explicit origin list:
const allowedOrigins = process.env.NODE_ENV === 'production'
? ['https://yourapp.com', 'https://staging.yourapp.com']
: ['http://localhost:3000', 'http://localhost:5173'];
app.use(cors({
origin: allowedOrigins,
credentials: true
}));
For FastAPI:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://yourapp.com"],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["Authorization", "Content-Type"],
)
The credentials: true flag matters here. Once you set it, browsers refuse origin: * -- they block that combination outright. Setting credentials forces you to be explicit about allowed origins. That is actually a useful constraint built into the CORS spec.
For local dev, add localhost to the list explicitly instead of defaulting to * and trying to remember to change it before shipping. That mental note gets forgotten.
One More Thing
If you have already shipped with wildcard CORS, check whether your auth relies on cookies or session tokens. If it does, credentials was probably off, which makes the wildcard less directly exploitable for authenticated requests -- but your public endpoints are still fully exposed. Lock it down regardless.
If you are on Next.js or Nuxt, check your next.config.js or nuxt.config.ts headers section. AI editors apply the same wildcard pattern there.
I've been running SafeWeave for this. It hooks into Cursor and Claude Code as an MCP server and flags wildcard CORS, missing rate limiting, CSRF gaps, and 9 other API posture issues before I move on. That said, a single semgrep rule matching cors() with no arguments catches the basic case in any CI pipeline. The important thing is catching it early, whatever tool you use.
Top comments (0)