# CORS is explicitly configured (not relying on framework defaults)

- **Pattern:** `ab-000282` (`ai-slop-security-theater.unapplied-middleware.cors-explicitly-configured`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000282
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000282)

## Why it matters

Calling `app.use(cors())` with no `origin:` option silently defaults to `Access-Control-Allow-Origin: *`, which allows any third-party domain to make cross-origin requests to your API and read the responses. OWASP A05 (Security Misconfiguration) and CWE-942 (Permissive Cross-domain Policy) both call this out. When combined with `credentials: true`, wildcard CORS causes browsers to reject the response anyway — but misconfigured CORS without credentials still exposes unauthenticated API responses to attacker-controlled sites.

## Severity rationale

Medium because wildcard CORS exposes unauthenticated API responses to any origin, enabling data exfiltration from endpoints that rely on same-origin as a defense.

## Remediation

Always pass an explicit `origin` list to the CORS configuration. Never rely on the default wildcard.

```ts
import cors from 'cors'

app.use(cors({
  origin: [
    'https://example.com',
    'https://app.example.com',
    process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : null,
  ].filter(Boolean),
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
}))
```

For Next.js, set `Access-Control-Allow-Origin` headers explicitly in `next.config.js` using the `headers()` function with per-path rules rather than installing the `cors` npm package.

## Detection

- **ID:** `cors-explicitly-configured`
- **Severity:** `medium`
- **What to look for:** When `cors`, `@fastify/cors`, `@koa/cors`, `next-connect-cors`, or similar CORS libraries are in `package.json` dependencies, walk source files for the import — at least 1 import required for this check to apply. Count all imports and verify a corresponding `.use(cors(`, `app.register(fastifyCors`, or `cors({...})` call exists with an explicit `origin:` option (not relying on the default `*`). EXCLUDE Next.js `next.config.js` `headers()` configurations that explicitly set `Access-Control-Allow-Origin` headers.
- **Pass criteria:** When a CORS library is imported, it is invoked AND the invocation passes an explicit `origin:` option that is NOT `'*'`. Report: "CORS library: [name] imported AND configured with explicit origin: [value]."
- **Fail criteria:** A CORS library is imported AND either (a) never invoked, OR (b) invoked with `origin: '*'` or no `origin:` option (which defaults to `*`).
- **Skip (N/A) when:** No CORS library in dependencies AND no Access-Control headers configured in `next.config.*`/`vercel.json`/`netlify.toml`.
- **Detail on fail:** `"cors imported in src/server.ts AND applied as app.use(cors()) without an origin option — defaults to allowing all origins"`
- **Remediation:** Default CORS allows any origin to call your API, defeating same-origin protection. Always specify allowed origins explicitly:

  ```ts
  // Bad: wildcard CORS
  app.use(cors())  // origin defaults to '*'

  // Good: explicit allowed origins
  app.use(cors({
    origin: ['https://example.com', 'https://app.example.com'],
    credentials: true,
  }))
  ```

## External references

- cwe CWE-942
- owasp A05
- owasp A01

Taxons: placeholder-hygiene, access-control

HTML version: https://auditbuffet.com/patterns/ab-000282
