Strict CORS Origin Allowlist Enforcement
Description
Server-side enforcement of a strict, explicitly enumerated origin allowlist for Cross-Origin Resource Sharing (CORS). The server validates the Origin header of every cross-origin request against a fixed allowlist and only responds with Access-Control-Allow-Origin for approved origins. Critically, the server never reflects the request's Origin header verbatim, never uses wildcard (*) with Access-Control-Allow-Credentials: true, and never relies on partial string matching or regex patterns that can be bypassed with attacker-controlled subdomains. For endpoints that handle credentials or session-sensitive data, Access-Control-Allow-Credentials is only set when the origin is explicitly trusted. This prevents cross-origin JavaScript from reading authenticated responses, exfiltrating session tokens, or making credentialed API calls from attacker-controlled pages.
CVSS Vector Impacts
| Metric | Transition | Rationale |
|---|---|---|
| Attack Complexity (AC) | L → H | Cross-origin credentialed reads go from trivially possible (wildcard or reflected-origin CORS) to requiring the attacker to compromise an explicitly allowed origin or find a CORS bypass. The mechanism is the server-side origin validation gate that rejects unapproved origins before including permissive CORS headers. This attenuation applies only to browser-mediated attack vectors; direct server-to-server requests are not subject to CORS enforcement. |
| Confidentiality (C) | H → L | The primary attack vector for CORS-based CWE-940 vulnerabilities is cross-origin data exfiltration via credentialed fetch/XHR. Strict CORS blocks the browser from delivering authenticated response data to the attacker's JavaScript, limiting confidentiality impact to data obtainable without credentials. This shift is browser-enforced and does not apply to non-browser attack vectors. |
CWE Relationships
Verification
Test that the server rejects unapproved origins and does not reflect arbitrary Origin headers in CORS response headers
# Expected: Empty output (no CORS headers returned for untrusted origin)
# Expected: Access-Control-Allow-Origin: https://trusted.example.com
# Expected: Empty output (no wildcard CORS or origin reflection patterns found)
Remediation
cat > /etc/nginx/conf.d/cme-914-cors.conf <<'EOF'
map $http_origin $cors_origin {
default "";
"https://<allowed_origin_1>" $http_origin;
"https://<allowed_origin_2>" $http_origin;
}
map $cors_origin $cors_credentials {
default "";
"~.+" "true";
}
# Apply in server or location blocks:
# add_header Access-Control-Allow-Origin $cors_origin always;
# add_header Access-Control-Allow-Credentials $cors_credentials always;
# add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
# add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
# if ($request_method = OPTIONS) { return 204; }
EOF
nginx -t
systemctl reload nginx
cat > /etc/httpd/conf.d/cme-914-cors.conf <<'EOF'
<IfModule mod_headers.c>
SetEnvIfNoCase Origin "^https://<allowed_origin_1>$" CORS_ORIGIN=$0
SetEnvIfNoCase Origin "^https://<allowed_origin_2>$" CORS_ORIGIN=$0
Header always set Access-Control-Allow-Origin %{CORS_ORIGIN}e env=CORS_ORIGIN
Header always set Access-Control-Allow-Credentials "true" env=CORS_ORIGIN
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS" env=CORS_ORIGIN
Header always set Access-Control-Allow-Headers "Authorization, Content-Type" env=CORS_ORIGIN
# Handle preflight
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteCond %{ENV:CORS_ORIGIN} .+
RewriteRule ^(.*)$ $1 [R=204,L]
</IfModule>
EOF
httpd -t 2>&1 || apachectl configtest 2>&1
systemctl reload httpd