-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathHeaderInjection.ql
More file actions
89 lines (80 loc) · 3.19 KB
/
HeaderInjection.ql
File metadata and controls
89 lines (80 loc) · 3.19 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
/**
* @name HTTP Header Injection
* @description User input should not be used in HTTP headers without first being escaped,
* otherwise a malicious user may be able to inject a value that could manipulate the response.
* @kind path-problem
* @problem.severity error
* @id python/header-injection
* @tags security
* external/cwe/cwe-113
* external/cwe/cwe-079
*/
// determine precision above
import python
import semmle.python.dataflow.new.RemoteFlowSources
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.ApiGraphs
import DataFlow::PathGraph
import semmle.python.frameworks.Flask
class WerkzeugHeader extends DataFlow::Node {
WerkzeugHeader() {
exists(DataFlow::CallCfgNode headerInstance, DataFlow::AttrRead addMethod |
headerInstance =
API::moduleImport("werkzeug").getMember("datastructures").getMember("Headers").getACall() and
addMethod.getAttributeName() = "add" and
addMethod.getObject().getALocalSource() = headerInstance and
this = addMethod.(DataFlow::CallCfgNode).getArg(1)
)
}
}
class FlaskHeader extends DataFlow::Node {
FlaskHeader() {
exists(
DataFlow::CallCfgNode headerInstance, DataFlow::AttrRead responseMethod,
AssignStmt sinkDeclaration
|
headerInstance = API::moduleImport("flask").getMember("Response").getACall() and
responseMethod.getAttributeName() = "headers" and
responseMethod.getObject().getALocalSource() = headerInstance and
sinkDeclaration.getATarget() = responseMethod.asExpr().getParentNode() and
this.asExpr() = sinkDeclaration.getValue()
)
}
}
class FlaskMakeResponse extends DataFlow::Node {
FlaskMakeResponse() {
exists(
DataFlow::CallCfgNode headerInstance, DataFlow::AttrRead responseMethod,
AssignStmt sinkDeclaration
|
headerInstance = API::moduleImport("flask").getMember("make_response").getACall() and
responseMethod.getAttributeName() = "headers" and
responseMethod.getObject().getALocalSource() = headerInstance and
(
sinkDeclaration.getATarget() = responseMethod.asExpr().getParentNode() and
this.asExpr() = sinkDeclaration.getValue()
)
//or
//extendMethod.getAttributeName() = "extend" and
//extendMethod.getObject().getALocalSource() = responseMethod and
//this = extendMethod.(DataFlow::CallCfgNode).getArg(0)
)
}
}
class HeaderInjectionSink extends DataFlow::Node {
HeaderInjectionSink() {
this instanceof WerkzeugHeader or
this instanceof FlaskHeader or
this instanceof FlaskMakeResponse
}
}
class HeaderInjectionFlowConfig extends TaintTracking::Configuration {
HeaderInjectionFlowConfig() { this = "HeaderInjectionFlowConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderInjectionSink }
}
from HeaderInjectionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ header is constructed from a $@.", sink.getNode(), "This",
source.getNode(), "user-provided value"