mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
JS: Enable association with headers without needing a route handler
Previously it was not possible to associate a ResponseSendArgument with its header definitions if they did not have the same route handler.
But for calls like `new Response(body, { headers })` the headers are fairly obvious whereas the route handler is unnecessarily hard to find. So we use the direct and obvious association between 'body' and 'headers' in the call.
This commit is contained in:
@@ -108,6 +108,12 @@ module Http {
|
||||
* Gets the route handler that sends this expression.
|
||||
*/
|
||||
abstract RouteHandler getRouteHandler();
|
||||
|
||||
/**
|
||||
* Gets a header definition associated with this response body, if it they are provided
|
||||
* by the same call.
|
||||
*/
|
||||
HeaderDefinition getAnAssociatedHeaderDefinition() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -93,4 +93,8 @@ private class ResponseSink extends Http::ResponseSendArgument {
|
||||
ResponseSink() { this = response.getArgument(0) }
|
||||
|
||||
override Http::RouteHandler getRouteHandler() { none() }
|
||||
|
||||
override ResponseArgumentHeaders getAnAssociatedHeaderDefinition() {
|
||||
result.getResponse() = response
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ module ReflectedXss {
|
||||
* Gets a HeaderDefinition that defines a XSS safe content-type for `send`.
|
||||
*/
|
||||
Http::HeaderDefinition getAXssSafeHeaderDefinition(Http::ResponseSendArgument send) {
|
||||
exists(Http::RouteHandler h |
|
||||
send.getRouteHandler() = h and
|
||||
result = xssSafeContentTypeHeader(h)
|
||||
|
|
||||
// The HeaderDefinition affects a response sent at `send`.
|
||||
isSafeContentTypeHeader(result) and
|
||||
(
|
||||
result = send.getAnAssociatedHeaderDefinition()
|
||||
or
|
||||
result = send.getRouteHandler().getAResponseHeader("content-type") and
|
||||
headerAffects(result, send)
|
||||
)
|
||||
}
|
||||
@@ -54,16 +54,22 @@ module ReflectedXss {
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `h` may send a response with a content type that is safe for XSS.
|
||||
*/
|
||||
Http::HeaderDefinition xssSafeContentTypeHeader(Http::RouteHandler h) {
|
||||
result = h.getAResponseHeader("content-type") and
|
||||
not exists(string tp | result.defines("content-type", tp) |
|
||||
private predicate isSafeContentTypeHeader(Http::HeaderDefinition header) {
|
||||
header.getAHeaderName() = "content-type" and
|
||||
not exists(string tp | header.defines("content-type", tp) |
|
||||
tp.toLowerCase().matches(xssUnsafeContentType() + "%")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `getAXssSafeHeaderDefinition` instead.
|
||||
* Holds if `h` may send a response with a content type that is safe for XSS.
|
||||
*/
|
||||
deprecated Http::HeaderDefinition xssSafeContentTypeHeader(Http::RouteHandler h) {
|
||||
result = h.getAResponseHeader("content-type") and
|
||||
isSafeContentTypeHeader(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a header set in `header` is likely to affect a response sent at `sender`.
|
||||
*/
|
||||
@@ -80,6 +86,8 @@ module ReflectedXss {
|
||||
dominatingHeader.getBasicBlock().(ReachableBasicBlock).dominates(sender.getBasicBlock())
|
||||
)
|
||||
)
|
||||
or
|
||||
header = sender.getAnAssociatedHeaderDefinition()
|
||||
}
|
||||
|
||||
bindingset[headerBlock]
|
||||
|
||||
@@ -43,14 +43,10 @@
|
||||
| response-object.js:9:18:9:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:9:18:9:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:10:18:10:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:10:18:10:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:11:18:11:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:11:18:11:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:13:18:13:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:13:18:13:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:14:18:14:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:14:18:14:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:16:18:16:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:16:18:16:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:17:18:17:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:17:18:17:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:20:18:20:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:20:18:20:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:23:18:23:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:23:18:23:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:26:18:26:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:26:18:26:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:30:18:30:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:30:18:30:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:34:18:34:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:34:18:34:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:38:18:38:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:38:18:38:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| tst2.js:7:12:7:12 | p | tst2.js:6:9:6:9 | p | tst2.js:7:12:7:12 | p | Cross-site scripting vulnerability due to a $@. | tst2.js:6:9:6:9 | p | user-provided value |
|
||||
@@ -165,14 +161,10 @@ edges
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:9:18:9:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:10:18:10:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:11:18:11:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:13:18:13:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:14:18:14:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:16:18:16:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:17:18:17:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:20:18:20:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:23:18:23:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:26:18:26:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:30:18:30:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:34:18:34:21 | data | provenance | |
|
||||
| response-object.js:7:11:7:25 | data | response-object.js:38:18:38:21 | data | provenance | |
|
||||
| response-object.js:7:18:7:25 | req.body | response-object.js:7:11:7:25 | data | provenance | |
|
||||
@@ -364,14 +356,10 @@ nodes
|
||||
| response-object.js:9:18:9:21 | data | semmle.label | data |
|
||||
| response-object.js:10:18:10:21 | data | semmle.label | data |
|
||||
| response-object.js:11:18:11:21 | data | semmle.label | data |
|
||||
| response-object.js:13:18:13:21 | data | semmle.label | data |
|
||||
| response-object.js:14:18:14:21 | data | semmle.label | data |
|
||||
| response-object.js:16:18:16:21 | data | semmle.label | data |
|
||||
| response-object.js:17:18:17:21 | data | semmle.label | data |
|
||||
| response-object.js:20:18:20:21 | data | semmle.label | data |
|
||||
| response-object.js:23:18:23:21 | data | semmle.label | data |
|
||||
| response-object.js:26:18:26:21 | data | semmle.label | data |
|
||||
| response-object.js:30:18:30:21 | data | semmle.label | data |
|
||||
| response-object.js:34:18:34:21 | data | semmle.label | data |
|
||||
| response-object.js:38:18:38:21 | data | semmle.label | data |
|
||||
| tst2.js:6:7:6:30 | p | semmle.label | p |
|
||||
|
||||
@@ -41,14 +41,10 @@
|
||||
| response-object.js:9:18:9:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:10:18:10:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:11:18:11:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:13:18:13:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:14:18:14:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:16:18:16:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:17:18:17:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:20:18:20:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:23:18:23:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:26:18:26:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:30:18:30:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:34:18:34:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| response-object.js:38:18:38:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
|
||||
| tst2.js:7:12:7:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:6:9:6:9 | p | user-provided value |
|
||||
|
||||
@@ -10,14 +10,14 @@ express().get('/foo', (req) => {
|
||||
new Response(data, {}); // $ Alert
|
||||
new Response(data, { headers: null }); // $ Alert
|
||||
|
||||
new Response(data, { headers: { 'content-type': 'text/plain'}}); // $ SPURIOUS: Alert
|
||||
new Response(data, { headers: { 'content-type': 'text/plain'}});
|
||||
new Response(data, { headers: { 'content-type': 'text/html'}}); // $ Alert
|
||||
|
||||
new Response(data, { headers: { 'Content-Type': 'text/plain'}}); // $ SPURIOUS: Alert
|
||||
new Response(data, { headers: { 'Content-Type': 'text/plain'}});
|
||||
new Response(data, { headers: { 'Content-Type': 'text/html'}}); // $ Alert
|
||||
|
||||
const headers1 = new Headers({ 'content-type': 'text/plain'});
|
||||
new Response(data, { headers: headers1 }); // $ SPURIOUS: Alert
|
||||
new Response(data, { headers: headers1 });
|
||||
|
||||
const headers2 = new Headers({ 'content-type': 'text/html'});
|
||||
new Response(data, { headers: headers2 }); // $ Alert
|
||||
@@ -27,7 +27,7 @@ express().get('/foo', (req) => {
|
||||
|
||||
const headers4 = new Headers();
|
||||
headers4.set('content-type', 'text/plain');
|
||||
new Response(data, { headers: headers4 }); // $ SPURIOUS: Alert
|
||||
new Response(data, { headers: headers4 });
|
||||
|
||||
const headers5 = new Headers();
|
||||
headers5.set('content-type', 'text/html');
|
||||
|
||||
Reference in New Issue
Block a user