Add query to detect CORS misconfiguration#542
Conversation
|
I'm running a scan on lgtm.com to see how many FPs there are because of checks on the user-provided values (scenarios like |
|
Are you done updating this? |
|
Also I note we already have CORS-related queries for JavaScript and Java; is this intended as a port of either one, or was it written from scratch? |
|
The only missing part is constraints to avoid false positives (in
I-don't-know-yet-what scenarios), and I haven't gotten to that yet.
I wrote the query from scratch. Didn't think to take a look at
implementations for other languages 😅
|
|
I scanned 3.743 projects, and got 39 results. Some of them were false positives, so I added a flag check that helps get rid of them. Some of the rest of the 39 are technically true positives, but do not lead to a security vulnerability scenario. |
|
Are you declaring this ready to review? |
|
Yes, I am. PR ready for review. |
|
I'll write today the issue for https://github.com/github/securitylab |
|
Aha, excellent -- in that case know that the seclab now do the early review stages (though I imagine since this is a well-known vuln category and produces good results, it'll come back to us in short order). I'll review once they're done commenting. |
|
Will they run the query on all go projects? |
|
Hi @gagliardetto, Browsers won't allow credentials in this case. You need to fix your tests in several places. Regarding the Example:, |
Thanks! I somehow managed to forget that part... |
Can we put that in the I tried to pick the most ambiguous and difficult result to exploit. Still, the query is public and can be run by anyone, so that doesn't really "protect" from disclosure. But I do understand that making things extra easy is not really a good thing. |
|
Great, I saw you have created github/securitylab#382 Imho, we expect people to provide some recent CVE (not too old, it still has to be relevant 😅), that could have been found with the query. That's why it can be a source snapshot from the past. Usual path is to look for advisories and say hey, my query would find the vuln in that revision before the fix. Finding a vuln in existing project is OK too, but you have to at least try to do a coordinated disclosure before dropping it publicly. It boils down to: is it real vulnerability that happens in real apps (proof) or just a made up assumption like if you pass untrusted input to |
Oh, I always thought that I had to provide CVEs that I had found and created thanks to the query. |
|
If you find at least 4 your name is Bug Slayer :D |
I like that phrasing; I'll add that. |
You are absolutely right. Daily realities sometimes diverge from the rightful and ideal path. I want to make sure the security lab can still catch them. |
|
|
||
| override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } | ||
|
|
||
| override predicate isSink(DataFlow::Node sink) { any() } |
There was a problem hiding this comment.
This can be very expensive. Instead of computing flow to absolutely any expression then filtering in isGuardedByCheckOnUntrusted, do your filtering here (i.e., first find if-conditions that control header writes, then enumerate interesting descendents of those if-conditions, which are either string-suffix checks or map-membership checks or equality test operands), then check for untrusted flow.
There was a problem hiding this comment.
Does it make more sense with how I updated it now? @smowton
| operand = child or | ||
| operand = child.(LorExpr).getAnOperand() or | ||
| operand = child.(LandExpr).getAnOperand() |
There was a problem hiding this comment.
Surely getAChildExpr() applied one more time takes care of cases 2 and 3?
There was a problem hiding this comment.
Not sure I follow what you mean here..
There was a problem hiding this comment.
I mean, you already use getAChildExpr*(), so why do you need to special-case LorExpr and LandExpr?
There was a problem hiding this comment.
You're right, it work without them.
There was a problem hiding this comment.
Wait, actually it doesn't
There was a problem hiding this comment.
Nope, my bad. Removed too much. It's all good.
|
Ping @smowton
|
|
All good now? @smowton |
| /** | ||
| * Holds if the provided `dst` is also destination of a `UntrustedFlowSource`. | ||
| */ | ||
| predicate flowsToGuardedByCheckOnUntrusted(HTTP::HeaderWrite allowOriginHW) { |
There was a problem hiding this comment.
Define a class for HeaderWrites that use the allow-origin key, and use that type for every allowOriginHW variable. Perhaps similarly allow-credentials HeaderWrites.
There was a problem hiding this comment.
Oh that's a lot more elegant. Love it.
Co-authored-by: Chris Smowton <smowton@github.com>
|
Is this good to go? |
|
Thank you @smowton ! |
This PR add a new experimental query that looks for misconfigured CORS headers that are too widely permissive on the accepted origins (i.e. set the
Access-Control-Allow-Originto unsafe values) while also allowing the inclusion of cookies on the request (i.e.Access-Control-Allow-Credentials: true).CWE-942: Permissive Cross-domain Policy with Untrusted Domains