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. Security https://sourcefeed.dev/c/security Article Cursor's CORS Fix Is a Critical Vulnerability 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 https://sourcefeed.dev/u/jiho 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 https://cwe.mitre.org/data/definitions/942.html , 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 https://cursor.com problem, but that's too narrow. The behavior shows up across Bolt https://bolt.new , Lovable https://lovable.dev , and plain Copilot https://github.com/features/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 https://www.veracode.com/resources/analyst-reports/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: js 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 https://www.npmjs.com/package/cors 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 for origin: true in the cors 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 with credentials: 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 does not echo 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 https://dev.to/c k fb750e731394/why-cursor-keeps-generating-wildcard-cors-headers-in-your-api-33ii — dev.to - 2025 GenAI Code Security Report https://www.veracode.com/resources/analyst-reports/2025-genai-code-security-report/ — veracode.com - CORS Misconfiguration in Vibe-Coded Apps: Wildcard Origins Explained https://vibedoctor.io/blog/sec-004-cors-misconfiguration-vibe-coded-apps — vibedoctor.io - CWE-942: Permissive Cross-domain Policy with Untrusted Domain https://cwe.mitre.org/data/definitions/942.html — cwe.mitre.org Ji-ho Choi https://sourcefeed.dev/u/jiho 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.