CORS misconfiguration for credentials transfer¶
ID: js/cors-misconfiguration-for-credentials Kind: path-problem Security severity: 7.5 Severity: error Precision: high Tags: - security - external/cwe/cwe-346 - external/cwe/cwe-639 - external/cwe/cwe-942 Query suites: - javascript-code-scanning.qls - javascript-security-extended.qls - javascript-security-and-quality.qls
Click to see the query in the CodeQL repository
A server can send the "Access-Control-Allow-Credentials"
CORS header to control when a browser may send user credentials in Cross-Origin HTTP requests.
When the Access-Control-Allow-Credentials
header is "true"
, the Access-Control-Allow-Origin
header must have a value different from "*"
in order to make browsers accept the header. Therefore, to allow multiple origins for Cross-Origin requests with credentials, the server must dynamically compute the value of the "Access-Control-Allow-Origin"
header. Computing this header value from information in the request to the server can therefore potentially allow an attacker to control the origins that the browser sends credentials to.
Recommendation¶
When the Access-Control-Allow-Credentials
header value is "true"
, a dynamic computation of the Access-Control-Allow-Origin
header must involve sanitization if it relies on user-controlled input.
Since the "null"
origin is easy to obtain for an attacker, it is never safe to use "null"
as the value of the Access-Control-Allow-Origin
header when the Access-Control-Allow-Credentials
header value is "true"
.
Example¶
In the example below, the server allows the browser to send user credentials in a Cross-Origin request. The request header origins
controls the allowed origins for such a Cross-Origin request.
varhttps=require('https'),url=require('url');varserver=https.createServer(function(){});server.on('request',function(req,res){letorigin=url.parse(req.url,true).query.origin;// BAD: attacker can choose the value of originres.setHeader("Access-Control-Allow-Origin",origin);res.setHeader("Access-Control-Allow-Credentials",true);// ...});
This is not secure, since an attacker can choose the value of the origin
request header to make the browser send credentials to their own server. The use of a whitelist containing allowed origins for the Cross-Origin request fixes the issue:
varhttps=require('https'),url=require('url');varserver=https.createServer(function(){});server.on('request',function(req,res){letorigin=url.parse(req.url,true).query.origin,whitelist={"https://example.com":true,"https://subdomain.example.com":true,"https://example.com:1337":true};if(origininwhitelist){// GOOD: the origin is in the whitelistres.setHeader("Access-Control-Allow-Origin",origin);res.setHeader("Access-Control-Allow-Credentials",true);}// ...});
References¶
Mozilla Developer Network: CORS, Access-Control-Allow-Origin.
Mozilla Developer Network: CORS, Access-Control-Allow-Credentials.
PortSwigger: Exploiting CORS Misconfigurations for Bitcoins and Bounties
Common Weakness Enumeration: CWE-346.
Common Weakness Enumeration: CWE-639.
Common Weakness Enumeration: CWE-942.