Query
Relevant PR: github/codeql-go#542
CVE ID(s)
No CVEs.
Report
After the addition of JavaScript to Netscape Navigator in 1995, it became necessary to introduce a security model that could limit the actions that an agent could undertake on behalf of the user. Before JavaScript, only the user could initiate actions.
The model that emerged is referred to as the "same-origin policy". Over time, many web-related technologies and vendors converged towards using some variant of it.
But as with many policies that regulate the web, over time, different needs and use-cases arise and require exceptions to those rules.
It's for that reason that the Cross-Origin Resource Sharing (CORS) mechanism was introduced. The Same-Origin Policy and CORS are sets of rules that limit what defines an origin and what are the sub-resources that are accessible within that origin or from an external origin.
As many developers may testify, CORS is hardly the easiest or the most stable or consistent standard they had to deal with during their careers.
CORS can be challenging with its limitations and confusing to the uninitiated. Frustration sometimes can lead to implementing solutions that open the doors to vulnerabilities.
This query targets exactly that: scenarios where the CORS permissions (for one reason or another) are too permissive.
Example Attack Scenario
You opened a new bank account at myexamplebank.xyz.
For some reason (maybe management, maybe regulation), there are multiple front-end subdomains in the format {region}.myexamplebank.xyz (in your case, it is us.myexamplebank.xyz), and there is only one API backend (api.myexamplebank.xyz).
Different domains (and subdomains) count as different origins, which means that api.myexamplebank.xyz has to implement CORS in order to be reachable from the various front-end subdomains.
When us.myexamplebank.xyz makes an API call to api.myexamplebank.xyz, your browser checks whether api.myexamplebank.xyz returns a CORS policy that allows it to be reached cross-origin from us.myexamplebank.xyz. If yes, then the request can go through, and you can successfully manage your bank account from us.myexamplebank.xyz.
Behind the scenes, api.myexamplebank.xyz needs to reply with a Access-Control-Allow-Origin: us.myexamplebank.xyz header when hit with a preflight CORS request sent by the browser with the OPTIONS method (plus some other CORS headers, like Access-Control-Allow-Credentials: true, which also allows sharing your cookies).
But the developers at your bank made a huge mistake (maybe because of continuous new regions that were added, or maybe because the CORS policies were too restrictive and continued to break the bank website as the browsers continue to slightly tweak the CORS rules and implementations, or maybe management just wanted so):
They made the CORS policy dependent on what the front-end request Origin header is, mirroring its value in the response Access-Control-Allow-Origin header value.
Examples:
- For the
us.myexamplebank.xyz origin, the api.myexamplebank.xyz will reply with Access-Control-Allow-Origin: us.myexamplebank.xyz.
- For the
japan.myexamplebank.xyz origin, the api.myexamplebank.xyz will reply with Access-Control-Allow-Origin: japan.myexamplebank.xyz.
- For the
eu.myexamplebank.xyz origin, the api.myexamplebank.xyz will reply with Access-Control-Allow-Origin: eu.myexamplebank.xyz.
The issue is that there were put no restrictions for this to happen:
- For the
evil.com origin, the api.myexamplebank.xyz will reply with Access-Control-Allow-Origin: evil.com.
Gotcha!
That opens up the doors for an attacker to transfer to themselves all your bank funds when you happen to load evil.com (or any other malicious domain), which will be allowed to access api.myexamplebank.xyz and make transactions on your behalf.
You might not even notice it while it is happening. You might be browsing the web and randomly end up on a malicious page that will want to access api.myexamplebank.xyz and leave you broke.
Result(s)
Provide at least one useful result found by your query, on some revision of a real project.
- Example:
- The
CORS function configures the CORS policy for all endpoint handlers, effectively being the one and only global CORS policy.
References
Query
Relevant PR: github/codeql-go#542
CVE ID(s)
No CVEs.
Report
After the addition of JavaScript to Netscape Navigator in 1995, it became necessary to introduce a security model that could limit the actions that an agent could undertake on behalf of the user. Before JavaScript, only the user could initiate actions.
The model that emerged is referred to as the "same-origin policy". Over time, many web-related technologies and vendors converged towards using some variant of it.
But as with many policies that regulate the web, over time, different needs and use-cases arise and require exceptions to those rules.
It's for that reason that the
Cross-Origin Resource Sharing (CORS)mechanism was introduced. The Same-Origin Policy and CORS are sets of rules that limit what defines an origin and what are the sub-resources that are accessible within that origin or from an external origin.As many developers may testify, CORS is hardly the easiest or the most stable or consistent standard they had to deal with during their careers.
CORS can be challenging with its limitations and confusing to the uninitiated. Frustration sometimes can lead to implementing solutions that open the doors to vulnerabilities.
This query targets exactly that: scenarios where the CORS permissions (for one reason or another) are too permissive.
Example Attack Scenario
You opened a new bank account at
myexamplebank.xyz.For some reason (maybe management, maybe regulation), there are multiple front-end subdomains in the format
{region}.myexamplebank.xyz(in your case, it isus.myexamplebank.xyz), and there is only one API backend (api.myexamplebank.xyz).Different domains (and subdomains) count as different origins, which means that
api.myexamplebank.xyzhas to implement CORS in order to be reachable from the various front-end subdomains.When
us.myexamplebank.xyzmakes an API call toapi.myexamplebank.xyz, your browser checks whetherapi.myexamplebank.xyzreturns a CORS policy that allows it to be reached cross-origin fromus.myexamplebank.xyz. If yes, then the request can go through, and you can successfully manage your bank account fromus.myexamplebank.xyz.Behind the scenes,
api.myexamplebank.xyzneeds to reply with aAccess-Control-Allow-Origin: us.myexamplebank.xyzheader when hit with a preflight CORS request sent by the browser with theOPTIONSmethod (plus some other CORS headers, likeAccess-Control-Allow-Credentials: true, which also allows sharing your cookies).But the developers at your bank made a huge mistake (maybe because of continuous new regions that were added, or maybe because the CORS policies were too restrictive and continued to break the bank website as the browsers continue to slightly tweak the CORS rules and implementations, or maybe management just wanted so):
They made the CORS policy dependent on what the front-end request
Originheader is, mirroring its value in the responseAccess-Control-Allow-Originheader value.Examples:
us.myexamplebank.xyzorigin, theapi.myexamplebank.xyzwill reply withAccess-Control-Allow-Origin: us.myexamplebank.xyz.japan.myexamplebank.xyzorigin, theapi.myexamplebank.xyzwill reply withAccess-Control-Allow-Origin: japan.myexamplebank.xyz.eu.myexamplebank.xyzorigin, theapi.myexamplebank.xyzwill reply withAccess-Control-Allow-Origin: eu.myexamplebank.xyz.The issue is that there were put no restrictions for this to happen:
evil.comorigin, theapi.myexamplebank.xyzwill reply withAccess-Control-Allow-Origin: evil.com.Gotcha!
That opens up the doors for an attacker to transfer to themselves all your bank funds when you happen to load
evil.com(or any other malicious domain), which will be allowed to accessapi.myexamplebank.xyzand make transactions on your behalf.You might not even notice it while it is happening. You might be browsing the web and randomly end up on a malicious page that will want to access
api.myexamplebank.xyzand leave you broke.Result(s)
Provide at least one useful result found by your query, on some revision of a real project.
CORSfunction configures the CORS policy for all endpoint handlers, effectively being the one and only global CORS policy.References