Your Website Shares Private Data With Any Other Website That Asks

Your server is configured to trust any website that contacts it, including malicious ones. This means if one of your logged-in users visits a harmful website, that site can silently pull data from your application — such as account details, API keys, or personal information — without the user knowing. Think of it like a bank teller who hands over account information to anyone who calls, as long as they say the right words.

Business Impact And Actions

high urgency

Business Impact

If your application handles user accounts, payments, or any sensitive data, this misconfiguration could expose that data to third-party websites. This creates real risk of customer data theft, which can trigger regulatory obligations (such as GDPR breach notifications), damage customer trust, and expose your business to liability. It may also flag as a finding in security audits or compliance reviews (SOC 2, ISO 27001, PCI DSS).

What To Do

  1. Ask your developer to replace the current 'allow any website' setting with a specific list of trusted domains that are allowed to access your application.
  2. If your application has an API used by a mobile app or third-party integration, make sure only those known domains are on the approved list.
  3. Ask your developer to verify the fix is in place by running a quick test (they can use a free online CORS checker or a curl command).
  4. If you use a CDN or reverse proxy (like Cloudflare, Nginx, or an AWS load balancer), confirm that CORS headers are only being set in one place — duplicates can cause the fix to be bypassed.

CORS Arbitrary Origin Reflection — Access-Control-Allow-Origin Mirrors Untrusted Request Header

high severity CVSS 7.4-8.1

Vulnerability Explanation

The server reads the incoming `Origin` request header and echoes it back verbatim in the `Access-Control-Allow-Origin` response header without validating it against an allowlist. When combined with `Access-Control-Allow-Credentials: true` (common in authenticated apps), this completely bypasses the browser's Same-Origin Policy: any attacker-controlled website can make credentialed cross-origin requests and read the full response. Even without the credentials header, unauthenticated API responses and public-but-sensitive data (API keys, tokens, internal metadata) are exposed to arbitrary origins.

Root Cause

Developers often implement dynamic origin reflection as a shortcut to support multiple legitimate origins (e.g., app.example.com and www.example.com) without maintaining an explicit allowlist. The code reads `request.headers['Origin']` and writes it directly into `Access-Control-Allow-Origin`, trusting the client-supplied value without any validation. This is functionally equivalent to `Access-Control-Allow-Origin: *` but worse — it also works with `Access-Control-Allow-Credentials: true`, which the wildcard does not.

Technical Impact

An attacker who tricks an authenticated user into visiting a malicious page can silently exfiltrate any data the user's session can access: account details, API keys, CSRF tokens, financial records, PII. With credentials enabled, the attack requires only a single cross-origin fetch. Without credentials, unauthenticated but sensitive responses (internal metadata, tokens in response bodies) are still exposed to any origin.

Severity Justification

Network-accessible, no privileges required, low attack complexity — attacker needs only to trick a user into visiting a malicious page (UI:R). Confidentiality and integrity impact are high when credentials are forwarded. CVSS vector aligns with CWE-942 / Acunetix published vector CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N for the credentialed variant.

Affected Components

  • Any server-side framework or web server reflecting Origin header without allowlist validation — all versions where this pattern is present

Remediation Steps

  1. Identify where CORS headers are set: search your codebase for 'Access-Control-Allow-Origin', 'Origin', and CORS middleware configuration. Also check Nginx/Apache configs and any CDN or proxy layer.
  2. Replace the reflection logic with an explicit allowlist. Validate the incoming Origin against a hardcoded or environment-variable-driven list of trusted origins, and only reflect it back if it matches. Reject (omit the header or return an error) for all other origins.
  3. Apply the fix at exactly one layer of your stack (application middleware OR web server — not both). Duplicate CORS headers from multiple layers cause conflicts and can reintroduce the vulnerability.
  4. Add `Vary: Origin` to all responses where `Access-Control-Allow-Origin` is set dynamically. This prevents CDN/proxy caches from serving a cached response with one origin's header to a different origin.
  5. Ensure OPTIONS preflight requests are handled correctly — they must return the same allowlist-validated `Access-Control-Allow-Origin` header.
  6. Test the fix: send a request with a spoofed Origin header (e.g., `curl -H 'Origin: https://evil.com' -I https://your-api.com`) and confirm the response does NOT reflect `https://evil.com` in `Access-Control-Allow-Origin`.

Verification Steps

  1. Run: `curl -H 'Origin: https://evil-cors-test.com' -I https://<your-domain>/api/` — the response should NOT contain `Access-Control-Allow-Origin: https://evil-cors-test.com`.
  2. Run: `curl -H 'Origin: https://your-trusted-domain.com' -I https://<your-domain>/api/` — the response SHOULD contain `Access-Control-Allow-Origin: https://your-trusted-domain.com`.
  3. Confirm `Vary: Origin` is present in the response headers when a valid origin is reflected.
  4. Use the free online tool at https://cors-test.codehappy.dev or browser DevTools (Network tab) to confirm cross-origin requests from untrusted origins are blocked.

Code Examples (javascript)

Vulnerable
// Node.js / Express — VULNERABLE: blindly reflects any origin
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', req.headers.origin); // ❌ No validation
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  next();
});
Fixed
// Node.js / Express — FIXED: allowlist validation
const cors = require('cors');

const ALLOWED_ORIGINS = [
  'https://www.example.com',
  'https://app.example.com'
];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || ALLOWED_ORIGINS.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Origin not allowed by CORS policy'));
    }
  },
  credentials: true
}));

// Django (settings.py) — FIXED
# pip install django-cors-headers
INSTALLED_APPS = ['corsheaders', ...]
MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware', ...] # Must be first
CORS_ALLOWED_ORIGINS = [
    'https://www.example.com',
    'https://app.example.com',
]
CORS_ALLOW_CREDENTIALS = True

# Nginx — FIXED: allowlist via map directive
# In nginx.conf http {} block:
map $http_origin $cors_origin {
    default "";
    "https://www.example.com" $http_origin;
    "https://app.example.com" $http_origin;
}
server {
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Vary Origin always;
}

Best Practices

  • Always validate the Origin header against a server-side allowlist of explicitly trusted domains — never reflect it without checking.
  • Add `Vary: Origin` whenever you dynamically set `Access-Control-Allow-Origin` to prevent cache poisoning at CDN/proxy layers.
  • Configure CORS at exactly one layer of your infrastructure (application middleware or web server, not both) to avoid conflicting or duplicate headers.
  • Store your allowed origins list in environment variables so it can differ between development and production without code changes.

Found this in your infrastructure?

VulWall scans for this and dozens of other issues automatically.

Scan Your Domain Free