Skip to content

Commit 8d0386b

Browse files
committed
Split into getNameArg and getValueArg
1 parent b10ade1 commit 8d0386b

File tree

5 files changed

+45
-16
lines changed

5 files changed

+45
-16
lines changed

python/ql/src/experimental/semmle/python/Concepts.qll

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,21 +150,26 @@ class LDAPEscape extends DataFlow::Node {
150150
/** Provides classes for modeling HTTP Header APIs. */
151151
module HeaderDeclaration {
152152
/**
153-
* A data-flow node that collects functions setting HTTP Headers' content.
153+
* A data-flow node that collects functions setting HTTP Headers.
154154
*
155155
* Extend this class to model new APIs. If you want to refine existing API models,
156156
* extend `HeaderDeclaration` instead.
157157
*/
158158
abstract class Range extends DataFlow::Node {
159+
/**
160+
* Gets the argument containing the header name.
161+
*/
162+
abstract DataFlow::Node getNameArg();
163+
159164
/**
160165
* Gets the argument containing the header value.
161166
*/
162-
abstract DataFlow::Node getAnInput();
167+
abstract DataFlow::Node getValueArg();
163168
}
164169
}
165170

166171
/**
167-
* A data-flow node that collects functions setting HTTP Headers' content.
172+
* A data-flow node that collects functions setting HTTP Headers.
168173
*
169174
* Extend this class to model new APIs. If you want to refine existing API models,
170175
* extend `HeaderDeclaration` instead.
@@ -175,7 +180,12 @@ class HeaderDeclaration extends DataFlow::Node {
175180
HeaderDeclaration() { this = range }
176181

177182
/**
178-
* Gets the argument containing the header value.
183+
* Gets the argument containing the header name.
179184
*/
180-
DataFlow::Node getAnInput() { result = range.getAnInput() }
185+
DataFlow::Node getNameArg() { result = range.getNameArg() }
186+
187+
/**
188+
* Gets the argument containing the header name.
189+
*/
190+
DataFlow::Node getValueArg() { result = range.getValueArg() }
181191
}

python/ql/src/experimental/semmle/python/frameworks/Django.qll

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ private module PrivateDjango {
5656
class DjangoResponseSetItemCall extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
5757
DjangoResponseSetItemCall() { this.getFunction() = headerSetItemCall() }
5858

59-
override DataFlow::Node getAnInput() { result = this.getArg([0, 1]) }
59+
override DataFlow::Node getNameArg() { result = this.getArg(0) }
60+
61+
override DataFlow::Node getValueArg() { result = this.getArg(1) }
6062
}
6163

6264
class DjangoResponseDefinition extends DataFlow::Node, HeaderDeclaration::Range {
@@ -67,9 +69,11 @@ private module PrivateDjango {
6769
headerInput.asCfgNode() = this.asCfgNode().(DefinitionNode).getValue()
6870
}
6971

70-
override DataFlow::Node getAnInput() {
71-
result.asExpr() in [headerInput.asExpr(), this.asExpr().(Subscript).getIndex()]
72+
override DataFlow::Node getNameArg() {
73+
result.asExpr() = this.asExpr().(Subscript).getIndex()
7274
}
75+
76+
override DataFlow::Node getValueArg() { result = headerInput }
7377
}
7478
}
7579
}

python/ql/src/experimental/semmle/python/frameworks/Flask.qll

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,31 @@ module ExperimentalFlask {
5454
headerInput.asCfgNode() = this.asCfgNode().(DefinitionNode).getValue()
5555
}
5656

57-
override DataFlow::Node getAnInput() {
58-
result.asExpr() in [headerInput.asExpr(), this.asExpr().(Subscript).getIndex()]
59-
}
57+
override DataFlow::Node getNameArg() { result.asExpr() = this.asExpr().(Subscript).getIndex() }
58+
59+
override DataFlow::Node getValueArg() { result = headerInput }
6060
}
6161

6262
private class FlaskMakeResponseExtend extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
63-
FlaskMakeResponseExtend() { this.getFunction() = headerInstanceCall() }
63+
KeyValuePair item;
64+
65+
FlaskMakeResponseExtend() {
66+
this.getFunction() = headerInstanceCall() and
67+
item = this.getArg(_).asExpr().(Dict).getAnItem()
68+
}
6469

65-
override DataFlow::Node getAnInput() { result = this.getArg(_) }
70+
override DataFlow::Node getNameArg() { result.asExpr() = item.getKey() }
71+
72+
override DataFlow::Node getValueArg() { result.asExpr() = item.getValue() }
6673
}
6774

6875
private class FlaskResponse extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
76+
KeyValuePair item;
77+
6978
FlaskResponse() { this = Flask::Response::classRef().getACall() }
7079

71-
override DataFlow::Node getAnInput() { result = this.getArgByName("headers") }
80+
override DataFlow::Node getNameArg() { result.asExpr() = item.getKey() }
81+
82+
override DataFlow::Node getValueArg() { result.asExpr() = item.getValue() }
7283
}
7384
}

python/ql/src/experimental/semmle/python/frameworks/Werkzeug.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ private module Werkzeug {
2424
this.getFunction().(DataFlow::AttrRead).getAttributeName() = "add"
2525
}
2626

27-
override DataFlow::Node getAnInput() { result = this.getArg(_) }
27+
override DataFlow::Node getNameArg() { result = this.getArg(0) }
28+
29+
override DataFlow::Node getValueArg() { result = this.getArg(1) }
2830
}
2931
}
3032
}

python/ql/src/experimental/semmle/python/security/injection/HTTPHeaders.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class HeaderInjectionFlowConfig extends TaintTracking::Configuration {
1313
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
1414

1515
override predicate isSink(DataFlow::Node sink) {
16-
sink = any(HeaderDeclaration headerDeclaration).getAnInput()
16+
exists(HeaderDeclaration headerDeclaration |
17+
sink in [headerDeclaration.getNameArg(), headerDeclaration.getValueArg()]
18+
)
1719
}
1820
}

0 commit comments

Comments
 (0)