Skip to content

Commit 060d0b4

Browse files
committed
Python: Remove imprecise container steps
- remove `tupleStoreStep` and `dictStoreStep` from `containerStep` These are imprecise compared to the content being precise. - add implicit reads to recover taint at sinks - add implicit read steps for decoders to supplement the `AdditionalTaintStep` that now only covers when the full container is tainted.
1 parent c7e3682 commit 060d0b4

File tree

16 files changed

+180
-55
lines changed

16 files changed

+180
-55
lines changed

python/ql/consistency-queries/DataFlowConsistency.ql

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ private module Input implements InputSig<Location, PythonDataFlow> {
3434
// parameter, but dataflow-consistency queries should _not_ complain about there not
3535
// being a post-update node for the synthetic `**kwargs` parameter.
3636
n instanceof SynthDictSplatParameterNode
37+
or
38+
Private::Conversions::readStep(n, _, _)
3739
}
3840

3941
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll

+36
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,8 @@ predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
928928
synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo)
929929
or
930930
VariableCapture::readStep(nodeFrom, c, nodeTo)
931+
or
932+
Conversions::readStep(nodeFrom, c, nodeTo)
931933
}
932934

933935
/** Data flows from a sequence to a subscript of the sequence. */
@@ -983,6 +985,40 @@ predicate attributeReadStep(Node nodeFrom, AttributeContent c, AttrRead nodeTo)
983985
nodeTo.accesses(nodeFrom, c.getAttribute())
984986
}
985987

988+
module Conversions {
989+
private import semmle.python.Concepts
990+
991+
predicate decoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) {
992+
exists(Decoding decoding |
993+
nodeFrom = decoding.getAnInput() and
994+
nodeTo = decoding.getOutput()
995+
) and
996+
(
997+
c instanceof TupleElementContent
998+
or
999+
c instanceof DictionaryElementContent
1000+
)
1001+
}
1002+
1003+
predicate encoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) {
1004+
exists(Encoding encoding |
1005+
nodeFrom = encoding.getAnInput() and
1006+
nodeTo = encoding.getOutput()
1007+
) and
1008+
(
1009+
c instanceof TupleElementContent
1010+
or
1011+
c instanceof DictionaryElementContent
1012+
)
1013+
}
1014+
1015+
predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
1016+
decoderReadStep(nodeFrom, c, nodeTo)
1017+
or
1018+
encoderReadStep(nodeFrom, c, nodeTo)
1019+
}
1020+
}
1021+
9861022
/**
9871023
* Holds if values stored inside content `c` are cleared at node `n`. For example,
9881024
* any value stored inside `f` is cleared at the pre-update node associated with `x`

python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll

+10-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,16 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
1616
* of `c` at sinks and inputs to additional taint steps.
1717
*/
1818
bindingset[node]
19-
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() }
19+
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) {
20+
// We allow implicit reads of precise content
21+
// imprecise content has already bubled up.
22+
exists(node) and
23+
(
24+
c instanceof DataFlow::TupleElementContent
25+
or
26+
c instanceof DataFlow::DictionaryElementContent
27+
)
28+
}
2029

2130
private module Cached {
2231
/**
@@ -178,10 +187,6 @@ predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
178187
or
179188
DataFlowPrivate::setStoreStep(nodeFrom, _, nodeTo)
180189
or
181-
DataFlowPrivate::tupleStoreStep(nodeFrom, _, nodeTo)
182-
or
183-
DataFlowPrivate::dictStoreStep(nodeFrom, _, nodeTo)
184-
or
185190
// comprehension, so there is taint-flow from `x` in `[x for x in xs]` to the
186191
// resulting list of the list-comprehension.
187192
//

python/ql/test/library-tests/dataflow/sensitive-data/test.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,5 @@ def call_wrapper(func):
131131
print(password) # $ SensitiveUse=password
132132
_config = {"sleep_timer": 5, "mysql_password": password}
133133

134-
# since we have taint-step from store of `password`, we will consider any item in the
135-
# dictionary to be a password :(
136-
print(_config["sleep_timer"]) # $ SPURIOUS: SensitiveUse=password
134+
# since we have precise dictionary content, other items of the config are not tainted
135+
print(_config["sleep_timer"])

python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def str_methods():
1717
ts.casefold(), # $ tainted
1818

1919
ts.format_map({}), # $ tainted
20-
"{unsafe}".format_map({"unsafe": ts}), # $ tainted
20+
"{unsafe}".format_map({"unsafe": ts}), # $ MISSING: tainted
2121
)
2222

2323

python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ def test_construction():
2929

3030
ensure_tainted(
3131
list(tainted_list), # $ tainted
32-
list(tainted_tuple), # $ tainted
32+
list(tainted_tuple), # $ MISSING: tainted
3333
list(tainted_set), # $ tainted
34-
list(tainted_dict.values()), # $ tainted
35-
list(tainted_dict.items()), # $ tainted
34+
list(tainted_dict.values()), # $ MISSING: tainted
35+
list(tainted_dict.items()), # $ MISSING: tainted
3636

3737
tuple(tainted_list), # $ tainted
3838
set(tainted_list), # $ tainted

python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def percent_fmt():
115115
ensure_tainted(
116116
tainted_fmt % (1, 2), # $ tainted
117117
"%s foo bar" % ts, # $ tainted
118-
"%s %s %s" % (1, 2, ts), # $ tainted
118+
"%s %s %s" % (1, 2, ts), # $ MISSING: tainted
119119
)
120120

121121

python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_unpacking.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def contrived_1():
5353

5454
(a, b, c), (d, e, f) = tainted_list, no_taint_list
5555
ensure_tainted(a, b, c) # $ tainted
56-
ensure_not_tainted(d, e, f) # $ SPURIOUS: tainted
56+
ensure_not_tainted(d, e, f)
5757

5858

5959
def contrived_2():

python/ql/test/library-tests/frameworks/stdlib/test_re.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@
7474
)
7575

7676
ensure_not_tainted(
77-
re.subn(pat, repl="safe", string=ts),
7877
re.subn(pat, repl="safe", string=ts)[1], # // the number of substitutions made
7978
)
8079
ensure_tainted(
80+
re.subn(pat, repl="safe", string=ts), # $ tainted // implicit read at sink
8181
re.subn(pat, repl="safe", string=ts)[0], # $ tainted // the string
8282
)

python/ql/test/library-tests/frameworks/tornado/taint_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def get(self, name = "World!", number="0", foo="foo"): # $ requestHandler route
6363
request.headers["header-name"], # $ tainted
6464
request.headers.get_list("header-name"), # $ tainted
6565
request.headers.get_all(), # $ tainted
66-
[(k, v) for (k, v) in request.headers.get_all()], # $ tainted
66+
[(k, v) for (k, v) in request.headers.get_all()], # $ MISSING: tainted
6767

6868
# Dict[str, http.cookies.Morsel]
6969
request.cookies, # $ tainted

python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
| hmac.new [**] | 1 | 1 |
12
| hmac.new [keyword msg] | 1 | 1 |
23
| hmac.new [position 1] | 1 | 1 |
34
| unknown.lib.func [keyword kw] | 2 | 1 |

python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ edges
1515
| test.py:23:16:23:27 | ControlFlowNode for Attribute | test.py:23:16:23:39 | ControlFlowNode for Attribute() | provenance | dict.get |
1616
| test.py:23:16:23:39 | ControlFlowNode for Attribute() | test.py:23:5:23:12 | ControlFlowNode for data_raw | provenance | |
1717
| test.py:24:5:24:8 | ControlFlowNode for data | test.py:25:44:25:47 | ControlFlowNode for data | provenance | |
18+
| test.py:24:5:24:8 | ControlFlowNode for data | test.py:25:44:25:47 | ControlFlowNode for data | provenance | |
19+
| test.py:25:44:25:47 | ControlFlowNode for data | test.py:25:15:25:74 | SynthDictSplatArgumentNode | provenance | |
1820
| test.py:34:5:34:8 | ControlFlowNode for data | test.py:35:10:35:13 | ControlFlowNode for data | provenance | |
1921
| test.py:34:5:34:8 | ControlFlowNode for data | test.py:36:13:36:16 | ControlFlowNode for data | provenance | |
2022
| test.py:34:12:34:18 | ControlFlowNode for request | test.py:34:12:34:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
@@ -45,6 +47,8 @@ nodes
4547
| test.py:23:16:23:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
4648
| test.py:23:16:23:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
4749
| test.py:24:5:24:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data |
50+
| test.py:25:15:25:74 | SynthDictSplatArgumentNode | semmle.label | SynthDictSplatArgumentNode |
51+
| test.py:25:44:25:47 | ControlFlowNode for data | semmle.label | ControlFlowNode for data |
4852
| test.py:25:44:25:47 | ControlFlowNode for data | semmle.label | ControlFlowNode for data |
4953
| test.py:34:5:34:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data |
5054
| test.py:34:12:34:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
@@ -68,6 +72,7 @@ nodes
6872
subpaths
6973
#select
7074
| test.py:15:36:15:39 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [position 1] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember |
75+
| test.py:25:15:25:74 | SynthDictSplatArgumentNode | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:15:25:74 | SynthDictSplatArgumentNode | Call to hmac.new [**] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember |
7176
| test.py:25:44:25:47 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:44:25:47 | ControlFlowNode for data | Call to hmac.new [keyword msg] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember |
7277
| test.py:35:10:35:13 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:35:10:35:13 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember |
7378
| test.py:36:13:36:16 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:36:13:36:16 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember |

python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ edges
77
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:50:16:50:32 | ControlFlowNode for format_error() | provenance | |
88
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | provenance | |
99
| test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | provenance | |
10-
| test.py:65:25:65:25 | ControlFlowNode for e | test.py:66:24:66:40 | ControlFlowNode for Dict | provenance | |
10+
| test.py:65:25:65:25 | ControlFlowNode for e | test.py:66:34:66:39 | ControlFlowNode for str() | provenance | |
11+
| test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | test.py:66:24:66:40 | ControlFlowNode for Dict | provenance | |
12+
| test.py:66:34:66:39 | ControlFlowNode for str() | test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | provenance | |
1113
nodes
1214
| test.py:16:16:16:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
1315
| test.py:23:25:23:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e |
@@ -23,6 +25,8 @@ nodes
2325
| test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
2426
| test.py:65:25:65:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e |
2527
| test.py:66:24:66:40 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
28+
| test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | semmle.label | ControlFlowNode for Dict [Dictionary element at key error] |
29+
| test.py:66:34:66:39 | ControlFlowNode for str() | semmle.label | ControlFlowNode for str() |
2630
subpaths
2731
| test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | test.py:50:16:50:32 | ControlFlowNode for format_error() |
2832
#select

python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected

-6
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ edges
2020
| test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | provenance | |
2121
| test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | provenance | |
2222
| test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | provenance | |
23-
| test.py:101:5:101:10 | ControlFlowNode for config | test.py:105:11:105:31 | ControlFlowNode for Subscript | provenance | |
24-
| test.py:103:21:103:37 | ControlFlowNode for Attribute | test.py:101:5:101:10 | ControlFlowNode for config | provenance | |
2523
nodes
2624
| test.py:19:5:19:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
2725
| test.py:19:16:19:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
@@ -62,9 +60,6 @@ nodes
6260
| test.py:70:15:70:25 | ControlFlowNode for bank_number | semmle.label | ControlFlowNode for bank_number |
6361
| test.py:73:15:73:17 | ControlFlowNode for ccn | semmle.label | ControlFlowNode for ccn |
6462
| test.py:74:15:74:22 | ControlFlowNode for user_ccn | semmle.label | ControlFlowNode for user_ccn |
65-
| test.py:101:5:101:10 | ControlFlowNode for config | semmle.label | ControlFlowNode for config |
66-
| test.py:103:21:103:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
67-
| test.py:105:11:105:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
6863
subpaths
6964
#select
7065
| test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
@@ -89,4 +84,3 @@ subpaths
8984
| test.py:70:15:70:25 | ControlFlowNode for bank_number | test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | This expression logs $@ as clear text. | test.py:67:38:67:48 | ControlFlowNode for bank_number | sensitive data (private) |
9085
| test.py:73:15:73:17 | ControlFlowNode for ccn | test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | This expression logs $@ as clear text. | test.py:67:76:67:78 | ControlFlowNode for ccn | sensitive data (private) |
9186
| test.py:74:15:74:22 | ControlFlowNode for user_ccn | test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | This expression logs $@ as clear text. | test.py:67:81:67:88 | ControlFlowNode for user_ccn | sensitive data (private) |
92-
| test.py:105:11:105:31 | ControlFlowNode for Subscript | test.py:103:21:103:37 | ControlFlowNode for Attribute | test.py:105:11:105:31 | ControlFlowNode for Subscript | This expression logs $@ as clear text. | test.py:103:21:103:37 | ControlFlowNode for Attribute | sensitive data (password) |

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected

-11
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ edges
55
| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | provenance | |
66
| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:38:17:38:23 | ControlFlowNode for request | provenance | |
77
| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | provenance | |
8-
| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:58:17:58:23 | ControlFlowNode for request | provenance | |
98
| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | provenance | |
109
| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:72:17:72:23 | ControlFlowNode for request | provenance | |
1110
| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:86:18:86:24 | ControlFlowNode for request | provenance | |
@@ -41,14 +40,9 @@ edges
4140
| full_partial_test.py:53:5:53:7 | ControlFlowNode for url | full_partial_test.py:54:18:54:20 | ControlFlowNode for url | provenance | |
4241
| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | full_partial_test.py:61:5:61:7 | ControlFlowNode for url | provenance | |
4342
| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | full_partial_test.py:64:5:64:7 | ControlFlowNode for url | provenance | |
44-
| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | full_partial_test.py:67:5:67:7 | ControlFlowNode for url | provenance | |
4543
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep |
46-
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:5:58:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep |
47-
| full_partial_test.py:58:5:58:13 | ControlFlowNode for query_val | full_partial_test.py:67:5:67:7 | ControlFlowNode for url | provenance | |
48-
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | full_partial_test.py:58:5:58:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep |
4944
| full_partial_test.py:61:5:61:7 | ControlFlowNode for url | full_partial_test.py:62:18:62:20 | ControlFlowNode for url | provenance | |
5045
| full_partial_test.py:64:5:64:7 | ControlFlowNode for url | full_partial_test.py:65:18:65:20 | ControlFlowNode for url | provenance | |
51-
| full_partial_test.py:67:5:67:7 | ControlFlowNode for url | full_partial_test.py:68:18:68:20 | ControlFlowNode for url | provenance | |
5246
| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:75:5:75:7 | ControlFlowNode for url | provenance | |
5347
| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:78:5:78:7 | ControlFlowNode for url | provenance | |
5448
| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:81:5:81:7 | ControlFlowNode for url | provenance | |
@@ -131,14 +125,10 @@ nodes
131125
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
132126
| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
133127
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
134-
| full_partial_test.py:58:5:58:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val |
135-
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
136128
| full_partial_test.py:61:5:61:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
137129
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
138130
| full_partial_test.py:64:5:64:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
139131
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
140-
| full_partial_test.py:67:5:67:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
141-
| full_partial_test.py:68:18:68:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
142132
| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
143133
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
144134
| full_partial_test.py:72:5:72:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val |
@@ -198,7 +188,6 @@ nodes
198188
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
199189
subpaths
200190
#select
201-
| full_partial_test.py:68:5:68:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:68:18:68:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value |
202191
| full_partial_test.py:89:5:89:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:89:18:89:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value |
203192
| full_partial_test.py:95:5:95:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:95:18:95:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value |
204193
| full_partial_test.py:101:5:101:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:101:18:101:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value |

0 commit comments

Comments
 (0)