DEV Community

Cover image for Why Cursor Keeps Writing Wildcard CORS (And Why It Matters)
Charles Kern
Charles Kern

Posted on

Why Cursor Keeps Writing Wildcard CORS (And Why It Matters)

TL;DR

  • AI editors default to app.use(cors()) -- allows every origin, always
  • The real risk hits when you add auth six days later and the CORS config never changes
  • Fix is eight lines but only matters if you apply it before credentials enter the picture

I shipped three side projects last year with Cursor doing the backend scaffolding. Every single one had the same CORS setup by the time I actually looked. Not because I asked for it explicitly -- because "set up CORS for my Express API" is the kind of prompt where AI defaults to the most permissive pattern it encountered during training.

The code runs. The frontend works. Nothing breaks. That is precisely why this one ships.

The vulnerable pattern (CWE-942)

// What Cursor generates for "add CORS to my Express app"
const cors = require('cors');
app.use(cors()); // no config = allow all origins, all methods, all headers
Enter fullscreen mode Exit fullscreen mode

Or slightly more explicit but just as permissive:

app.use(cors({ origin: '*' }));
Enter fullscreen mode Exit fullscreen mode

For a stateless API -- no cookies, no Authorization headers -- wildcard CORS is mostly harmless. The problem is that real APIs do not stay stateless. You add JWT auth a week later. You drop in a session cookie. The CORS config stays where it is because it was working and nobody flagged it.

Now you have Access-Control-Allow-Origin: * on an authenticated API. Any site can make credentialed cross-origin requests to your endpoints. The browser spec actually blocks * with credentials: true -- but misconfigured apps often reach for origin: req.headers.origin as a "fix" for the browser error, which just shifts the problem from a wildcard to a reflected-origin setup. Reflected origin is arguably worse: it looks intentional.

Why AI keeps generating this

The pattern comes from the highest-voted Express CORS answers on Stack Overflow, written between 2016 and 2020. app.use(cors()) is the answer that solves the developer's immediate problem -- the browser CORS error -- with zero config. LLMs trained on this data reproduce it at high confidence because it works for the stated constraint.

There is no feedback loop. The AI does not know whether your API will need credentials later. It satisfies what you asked for.

The fix

const allowedOrigins = [
  'https://yourdomain.com',
  'http://localhost:3000' // remove before production
];

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

Two things to note. First, credentials: true is required if you're using cookies or Authorization headers cross-origin -- but the spec explicitly blocks origin: '*' combined with credentials: true, so you must use an explicit allowlist. Second, if your platform injects CORS headers at the edge (Cloudflare Workers, AWS API Gateway, Railway's proxy layer), your application-level config may be overridden or ignored. Check both layers.

The !origin check handles same-origin requests and server-to-server calls where Origin is not sent. Without it, your own backend-to-backend calls will fail in production.

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)