TL;DR
- Cursor generates
cors({ origin: '*' })on nearly every Express app it builds - Wildcard CORS + Bearer tokens in localStorage means any site can make authenticated requests on behalf of your users
- One-line fix: replace
'*'with an explicit origin allowlist
I was reviewing a side project last week. A Node/Express REST API built almost entirely with Cursor. The developer was sharp. The code was clean. The CORS config was a disaster.
Every single endpoint was configured with app.use(cors({ origin: '*' })). The app handled user accounts, subscription data, and a connected Stripe integration. Wide open to any origin on the internet.
I've seen this exact pattern in a dozen Cursor-generated projects now. It's not a Cursor bug. It's a training data problem.
The Vulnerable Code (CWE-942)
Here's what Cursor produces when you ask it to add CORS to an Express app:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({ origin: '*' })); // added by AI -- CWE-942
app.get('/api/account', authenticate, (req, res) => {
const user = await User.findById(req.user.id);
res.json(user);
});
app.post('/api/transfer', authenticate, async (req, res) => {
await processTransfer(req.body);
res.json({ success: true });
});
This is copied directly from countless Express + CORS tutorials written between 2015 and 2022. They all use origin: '*'. AI models trained on that corpus reproduce it faithfully.
Why Wildcard CORS Matters on an API With Auth
The most common pushback: if my endpoints require authentication, doesn't that protect them?
Partially. Browsers block credentials: true with a wildcard origin. That's in the CORS spec. But without credentials, a wildcard still lets any site read your API responses and probe your endpoints.
Here's where it gets sharper: most AI-generated apps use Bearer token auth via Authorization headers, with tokens stored in localStorage. The browser CORS restriction on credentials: true only applies to cookies. If your app uses header-based auth, wildcard CORS doesn't protect you the way you might think.
An attacker on evil.com can make a fetch request to your API. If the user has a token in localStorage, that token goes in the Authorization header. No cookies involved. No credential flag needed. Your API responds with full user data.
The Fix
Replace the wildcard with an explicit allowlist. The function form handles multi-environment setups cleanly:
const allowedOrigins = [
'https://yourapp.com',
'https://staging.yourapp.com',
process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : null
].filter(Boolean);
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
One thing easy to miss: calling cors() with no arguments is the same as cors({ origin: '*' }). Cursor generates both variants. Run these two greps:
grep -r "origin: '\*'" ./src
grep -r 'cors()' ./src
The second one catches silent wildcard configs that look like a harmless no-config default.
I've been running SafeWeave for this. It hooks into Cursor and Claude Code as an MCP server and flags these patterns before I move on. That said, even a basic pre-commit hook with semgrep and gitleaks will catch most of what's in this post. The important thing is catching it early, whatever tool you use.
Top comments (0)