cd /news/ai-safety/cursor-s-cors-fix-is-a-critical-vuln… Β· home β€Ί topics β€Ί ai-safety β€Ί article
[ARTICLE Β· art-73823] src=sourcefeed.dev β†— pub= topic=ai-safety verified=true sentiment=↓ negative

Cursor's CORS Fix Is a Critical Vulnerability

Cursor, Bolt, Lovable, and GitHub Copilot AI coding assistants frequently generate CORS middleware that reflects the incoming Origin header with credentials enabled, creating a critical vulnerability (CWE-942) that allows any website to read authenticated API responses on a logged-in user's behalf. Veracode's 2025 GenAI Code Security Report found that when tasks offered both secure and insecure implementations, models chose the insecure path 45% of the time, with CORS reflection being a textbook example. Security researcher Ji-ho Choi warns that the fix must be external to the generation step, as prompting alone cannot reliably produce secure code.

read6 min views1 publishedJul 26, 2026
Cursor's CORS Fix Is a Critical Vulnerability
Image: Sourcefeed (auto-discovered)

SecurityArticle

AI assistants keep reflecting the Origin header with credentials on β€” the one pattern that turns an authenticated API into an open door.

Ji-ho Choi

Ask Cursor to fix a CORS error and there's a good chance it hands you a critical vulnerability with a green checkmark. Not a wildcard *

β€” that one's mostly harmless because browsers refuse to pair it with credentials. The dangerous pattern is subtler: middleware that reads the incoming Origin

header and echoes it straight back into Access-Control-Allow-Origin

, alongside Access-Control-Allow-Credentials: true

. It works flawlessly in local dev. It ships. And it turns your authenticated API into something any website on the internet can read on a logged-in user's behalf.

Why the model reaches for reflection #

CORS errors are among the most common friction points in web development, and they share a frustrating property: the browser tells you what it wants but the fix is never one obvious line. You're running the frontend on localhost:3000

, the API on localhost:8000

, a preview build on some Vercel URL, maybe Postman or a mobile simulator hitting the same backend. Every one of those is a distinct origin. An allowlist has to enumerate all of them and stay current. Reflection doesn't β€” it says yes to whoever asks.

res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Credentials', 'true');

From a language model's perspective this is the global maximum. It resolves the error for every dev port, every tool, every teammate, on the first try, with no follow-up questions. The training corpus is saturated with Stack Overflow answers that do exactly this because they, too, were optimizing for "make the red text go away." As one writeup on the pattern put it, the fastest way to make a CORS error disappear is to stop checking who's asking. The model learned that lesson well.

The tell is that req.headers.origin

is attacker-controlled. A malicious page sets Origin: https://your-api.example

β€” no, it sets whatever it likes, Origin: https://evil.test

, and the server dutifully reflects evil.test

back. The browser sees the response origin match the request origin, sees credentials allowed, and releases the victim's session cookie along with the response body. Same-origin policy, the thing that's supposed to stop cross-site reads, has been explicitly waived by your own server. This is CWE-942, permissive cross-domain policy, and it reads as critical on any scanner because it is one.

This isn't a Cursor bug #

It's tempting to frame this as a Cursor problem, but that's too narrow. The behavior shows up across Bolt, Lovable, and plain Copilot completions, because they draw on the same corpus and optimize for the same signal: does the code run. Veracode's 2025 GenAI Code Security Report, which ran 80 curated tasks across more than 100 models, found that when a task offered both a secure and an insecure way to write something, the models picked the insecure path 45% of the time. CORS is a textbook instance of that split: the secure version costs an extra function and a config array, the insecure version is shorter and passes the same functional test.

That framing matters because it tells you where the fix has to live. You cannot prompt your way to safety reliably β€” "write secure CORS" nudges the odds but doesn't close the gap, because the model's notion of "works" and your notion of "safe" diverge precisely here. The check has to be external to the generation step.

What the correct version actually costs #

The secure pattern is not exotic. It's an allowlist and a callback:

const allowedOrigins = new Set([
  'https://app.example.com',
  'https://staging.example.com',
]);

app.use(cors({
  origin(origin, cb) {
    // no Origin header = same-origin or a non-browser client (curl, server-to-server)
    if (!origin || allowedOrigins.has(origin)) return cb(null, true);
    return cb(new Error('Not allowed by CORS'));
  },
  credentials: true,
}));

The cors middleware does the right thing here: it only emits

Access-Control-Allow-Origin

when the origin is on the list, and it never falls back to a wildcard. Flask's flask-cors

and most framework equivalents take the same explicit-list shape. The cost is real but small β€” you maintain a list, and you plumb your preview and staging URLs into it, usually from an environment variable so the list differs per deployment.One caveat worth stating plainly, because a lot of the "just use an allowlist" advice glosses it: locking down CORS is not CSRF protection. CORS governs whether a cross-origin script can read your response. It does nothing to stop a cross-site request from being sent and having side effects. If your API mutates state on cookie auth, you still want SameSite=Lax

or Strict

cookies and, for anything sensitive, CSRF tokens. Reflection-plus-credentials is worse than a missing allowlist because it defeats both layers at once, but fixing the read side doesn't absolve you of the write side.

The workflow change this demands #

If you're shipping AI-generated backends, treat CORS config as a review chokepoint, not a line you skim. Concretely:

  • Grep your codebase for Access-Control-Allow-Origin

set from a request header, and fororigin: true

in thecors

middleware β€” that's the reflect-everything switch in disguise. - Add a CI check. It's a one-line static rule: flag any response that sets ACAO from req.headers.origin

or pairs a reflected/wildcard origin withcredentials: true

. This catches the regression the model reintroduces every time someone asks it to fix a new preview URL. - Test it adversarially, not functionally. Fire a request with Origin: https://not-your-app.test

and assert the response doesnotecho it back. Your normal test suite won't catch this because your tests come from allowed origins.

The broader lesson is that AI assistants have quietly shifted where security bugs enter. They don't write novel, exotic flaws β€” they industrialize the well-known ones, reproducing the most common insecure Stack Overflow answer at the speed of autocomplete and with the confidence of a passing local test. CORS reflection is the current poster child because it's invisible until a scanner or a pentester flags it, and by then it's in production behind a login. The defense isn't better prompts. It's assuming the generated config is wrong about trust boundaries until a check you control proves otherwise.

Sources & further reading #

Why Cursor Keeps Generating Wildcard CORS Headers in Your APIβ€” dev.to - 2025 GenAI Code Security Reportβ€” veracode.com - CORS Misconfiguration in Vibe-Coded Apps: Wildcard Origins Explainedβ€” vibedoctor.io - CWE-942: Permissive Cross-domain Policy with Untrusted Domainβ€” cwe.mitre.org

Ji-ho ChoiΒ· Security & Cloud Editor

Ji-ho covers the increasingly tangled overlap between cloud architecture and security, drawing on a background as a penetration tester to keep his reporting grounded in real-world attack paths. He never lets a vendor claim go unquestioned and insists that every buzzword come with a proof of concept.

Discussion 0 #

No comments yet

Be the first to weigh in.

── more in #ai-safety 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/cursor-s-cors-fix-is…] indexed:0 read:6min 2026-07-26 Β· β€”