CWE-942 / High

CORS Misconfigurations (CWE-942): Origin Reflection & Credentials Leaks

How reflecting untrusted Origin headers and combining Access-Control-Allow-Origin with Allow-Credentials exposes authenticated APIs to cross-site data theft.

💡 Plain English Explainer (ELI5)

The Same-Origin Policy stops evil.com from reading your emails on gmail.com. CORS is an exception mechanism: gmail.com can say 'I officially give evil.com permission to read my user's data'. A CORS misconfiguration is when a lazy developer writes code that says 'Whoever is asking, copy their name and give them permission to read everything, including login cookies'.

Core Concepts & Key Terms

Same-Origin Policy (SOP)
The fundamental browser security rule preventing scripts on one origin from reading responses from a different origin.
Access-Control-Allow-Origin (ACAO)
The HTTP response header declaring which origin is permitted to read the resource.
Access-Control-Allow-Credentials (ACAC)
When set to `true`, permits browsers to expose sensitive responses to JavaScript when cookies/auth headers were attached.
Origin Reflection
The vulnerable practice of reading the incoming `Origin` request header and copying it straight into `ACAO`.

Step-by-Step Attack Flow

Step 1

1. Victim Visits Malicious Origin

A logged-in user visits attacker-site.com.

Step 2

2. Cross-Origin Fetch with Credentials

The malicious site executes: fetch('https://api.target.com/user/private-keys', {credentials: 'include'}).

Step 3

3. Backend Dynamically Mirrors Origin

The server receives Origin: https://attacker-site.com and responds with Access-Control-Allow-Origin: https://attacker-site.com and Access-Control-Allow-Credentials: true.

Step 4

4. SOP Bypass & Data Exfiltration

The browser allows attacker-site.com to read the victim's private API response and transmit it to the attacker's collection server.

Source Code: Flaw vs. Secure Implementation

VULNERABLE PATTERN
// VULNERABLE: Dynamic Origin Reflection with Credentials
const express = require("express");
const app = express();

app.use((req, res, next) => {
  // CRITICAL SECURITY FLAW: Reflects any untrusted Origin header
  // Combined with credentials: true, completely dismantles the Same-Origin Policy!
  const origin = req.headers.origin;
  if (origin) {
    res.setHeader("Access-Control-Allow-Origin", origin);
    res.setHeader("Access-Control-Allow-Credentials", "true");
  }
  next();
});

app.get("/api/account/data", (req, res) => {
  res.json({ ssn: "123-45-6789", balance: 95000 });
});
HARDENED DEFENSE
// SECURE: Strict Explicit Origin Allowlist & Zero Credentials on Public APIs
const express = require("express");
const app = express();

const TRUSTED_ORIGINS = new Set([
  "https://dashboard.example.com",
  "https://admin.example.com"
]);

app.use((req, res, next) => {
  const origin = req.headers.origin;
  
  if (origin && TRUSTED_ORIGINS.has(origin)) {
    // Only permit explicitly enumerated, trusted internal domains
    res.setHeader("Access-Control-Allow-Origin", origin);
    res.setHeader("Access-Control-Allow-Credentials", "true");
    res.setHeader("Vary", "Origin");
  } else {
    // Untrusted origins receive NO access control permission headers
    res.removeHeader("Access-Control-Allow-Origin");
  }
  next();
});

Engineering Hardening Checklist

← Browse Full Security Directory Explore Vulnerability Playbooks →