forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWebResponse.qll
More file actions
103 lines (83 loc) · 3.08 KB
/
WebResponse.qll
File metadata and controls
103 lines (83 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
* Models the `Request` and `Response` objects from the Web standards.
*/
private import javascript
/** Treats `Response` as an entry point for API graphs. */
private class ResponseEntryPoint extends API::EntryPoint {
ResponseEntryPoint() { this = "global.Response" }
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Response") }
}
/** Treats `Headers` as an entry point for API graphs. */
private class HeadersEntryPoint extends API::EntryPoint {
HeadersEntryPoint() { this = "global.Headers" }
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Headers") }
}
/**
* A call to the `Response` and `NextResponse` constructor.
*/
private class ResponseCall extends API::InvokeNode {
ResponseCall() {
this = any(ResponseEntryPoint e).getANode().getAnInstantiation() or
this = API::moduleImport("next/server").getMember("NextResponse").getAnInstantiation()
}
}
/**
* A call to the `Headers` constructor.
*/
private class HeadersCall extends API::InvokeNode {
HeadersCall() { this = any(HeadersEntryPoint e).getANode().getAnInstantiation() }
}
/**
* The `headers` in `new Response(body, { headers })`
*/
private class ResponseArgumentHeaders extends Http::HeaderDefinition {
private ResponseCall response;
private API::Node headerNode;
ResponseArgumentHeaders() {
headerNode = response.getParameter(1).getMember("headers") and
this = headerNode.asSink()
}
ResponseCall getResponse() { result = response }
/**
* Gets a call to `new Headers()` that is passed as the headers to this call.
*/
private HeadersCall getHeadersCall() { headerNode.refersTo(result.getReturn()) }
/**
* Gets an object whose properties are interpreted as headers, such as `{'content-type': 'foo'}`.
*/
private API::Node getAPlainHeaderObject() {
// new Response(body, {...})
result = headerNode
or
// new Response(body, new Headers({...}))
result = this.getHeadersCall().getParameter(0)
}
private API::Node getHeaderNode(string headerName) {
exists(string prop |
result = this.getAPlainHeaderObject().getMember(prop) and
headerName = prop.toLowerCase()
)
or
exists(API::CallNode append |
append = this.getHeadersCall().getReturn().getMember(["append", "set"]).getACall() and
headerName = append.getArgument(0).getStringValue().toLowerCase() and
result = append.getParameter(1)
)
}
override predicate defines(string headerName, string headerValue) {
this.getHeaderNode(headerName).getAValueReachingSink().getStringValue() = headerValue
}
override string getAHeaderName() { exists(this.getHeaderNode(result)) }
override Http::RouteHandler getRouteHandler() { none() }
}
/**
* Data passed as the body in `new Response(body, ...)`.
*/
private class ResponseSink extends Http::ResponseSendArgument {
private ResponseCall response;
ResponseSink() { this = response.getArgument(0) }
override Http::RouteHandler getRouteHandler() { none() }
override ResponseArgumentHeaders getAnAssociatedHeaderDefinition() {
result.getResponse() = response
}
}