cd /news/ai-tools/why-cursor-keeps-generating-wildcard… · home topics ai-tools article
[ARTICLE · art-72327] src=dev.to ↗ pub= topic=ai-tools verified=true sentiment=↓ negative

Why Cursor Keeps Generating Wildcard CORS Headers in Your API

A developer discovered that the AI code editor Cursor fixed a CORS error in their side project by generating middleware that uses origin reflection, a pattern that echoes back any Origin header sent by the requester. This creates a security vulnerability (CWE-942) that allows any website to read authenticated API responses by sending a matching Origin header. The developer warns that AI editors reproduce this pattern because training data skews toward the fastest fix that works everywhere, and recommends replacing origin reflection with an explicit allowlist of trusted domains.

read3 min views1 publishedJul 24, 2026

I hit a CORS error in a side project last week. Frontend on one port, API on another, browser blocking the request. I asked Cursor to fix it, and it did, instantly. The error went away. I moved on to the actual feature I was building.

Three days later I was reading through the generated middleware for something unrelated and noticed what "fixed" actually meant. It hadn't allowlisted my frontend's origin. It had told the server to accept requests from anywhere, with cookies attached.

That's the trade AI editors make by default. You ask for the error to go away, and the fastest way to make a CORS error go away is to stop checking who's asking.

The pattern shows up as origin reflection, not a plain wildcard. A bare Access-Control-Allow-Origin: *

combined with Access-Control-Allow-Credentials: true

actually gets rejected by the browser, so tutorials work around that by echoing back whatever Origin header the request sent. That workaround is the vulnerability.

// ❌ CWE-942: Permissive Cross-domain Policy
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', req.headers.origin);
  res.header('Access-Control-Allow-Credentials', 'true');
  res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
  next();
});

req.headers.origin

is a value the requester controls. A page hosted on evil-site.com

sends Origin: evil-site.com

, the server echoes it straight back, and the browser sees a match. Credentials are allowed, so the victim's session cookie rides along. Any authenticated GET or POST your API exposes is now readable and callable from a page the victim never meant to trust.

Origin reflection survives in training data because it's the fastest fix that makes a CORS error disappear in local development, and almost every public snippet optimizes for that. Stack Overflow answers, boilerplate repos, and "quick fix" gists all reach for the same three lines because they work identically whether you're testing on localhost:3000

, localhost:5173

, or a Vercel preview URL. Nobody has to think about which origins are actually supposed to be allowed.

An explicit allowlist requires knowing your production frontend's domain ahead of time, which isn't information available in an isolated code snippet. So the training data skews toward the version that works everywhere and restricts nothing. AI editors reproduce that pattern faithfully, and it ships because it passes every test a developer actually runs before deploying.

Replace origin reflection with a fixed list of domains you actually trust, checked explicitly against each incoming request.

// ✅ Explicit allowlist, no reflection
const allowedOrigins = [
  'https://app.example.com',
  'https://admin.example.com'
];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true
}));

Python/Flask version of the same fix:

from flask_cors import CORS

CORS(
    app,
    origins=["https://app.example.com", "https://admin.example.com"],
    supports_credentials=True
)

For local development, add localhost

ports to the allowlist explicitly rather than falling back to a wildcard or reflection "just for now." Environment variables work well here: one allowlist for dev, a locked-down one for production, both explicit.

Q: Is Access-Control-Allow-Origin: * with credentials actually dangerous?

Q: Does a CORS allowlist replace authentication?

A: No. CORS controls which browser-based origins can read a response, not who's authorized to call the endpoint. You still need real auth checks; CORS is a second layer that stops the browser from letting an untrusted page use a victim's session.

Q: How do I check my API for this right now?

A: Look for any CORS middleware where the Access-Control-Allow-Origin

value comes from a request header instead of a fixed list. If you see req.headers.origin

or req.get('origin')

written straight into the response, that's the pattern.

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. 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.

── more in #ai-tools 4 stories · sorted by recency
── more on @cursor 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/why-cursor-keeps-gen…] indexed:0 read:3min 2026-07-24 ·