Skip to content

Commit 0439b83

Browse files
committed
Python: Taint when using unicode
1 parent 2a29e26 commit 0439b83

File tree

3 files changed

+76
-70
lines changed

3 files changed

+76
-70
lines changed

python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,7 @@ predicate subscriptStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
6767
predicate stringMethods(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
6868
// transforming something tainted into a string will make the string tainted
6969
exists(CallNode call | call = nodeTo.getNode() |
70-
(
71-
call.getFunction().(NameNode).getId() = "str"
72-
or
73-
call.getFunction().(NameNode).getId() = "bytes"
74-
) and
70+
call.getFunction().(NameNode).getId() in ["str", "bytes", "unicode"] and
7571
(
7672
nodeFrom.getNode() = call.getArg(0)
7773
or
Lines changed: 65 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,65 @@
1-
| test.py:24 | ok | str_operations | ts |
2-
| test.py:25 | ok | str_operations | BinaryExpr |
3-
| test.py:26 | ok | str_operations | BinaryExpr |
4-
| test.py:27 | ok | str_operations | BinaryExpr |
5-
| test.py:28 | ok | str_operations | ts[Slice] |
6-
| test.py:29 | ok | str_operations | ts[Slice] |
7-
| test.py:30 | ok | str_operations | ts[Slice] |
8-
| test.py:31 | ok | str_operations | ts[0] |
9-
| test.py:32 | ok | str_operations | str(..) |
10-
| test.py:33 | ok | str_operations | bytes(..) |
11-
| test.py:42 | ok | str_methods | ts.capitalize() |
12-
| test.py:43 | ok | str_methods | ts.casefold() |
13-
| test.py:44 | ok | str_methods | ts.center(..) |
14-
| test.py:45 | ok | str_methods | ts.expandtabs() |
15-
| test.py:47 | ok | str_methods | ts.format() |
16-
| test.py:48 | ok | str_methods | "{}".format(..) |
17-
| test.py:49 | ok | str_methods | "{unsafe}".format(..) |
18-
| test.py:51 | ok | str_methods | ts.format_map(..) |
19-
| test.py:52 | fail | str_methods | "{unsafe}".format_map(..) |
20-
| test.py:54 | ok | str_methods | ts.join(..) |
21-
| test.py:55 | fail | str_methods | "".join(..) |
22-
| test.py:57 | ok | str_methods | ts.ljust(..) |
23-
| test.py:58 | ok | str_methods | ts.lstrip() |
24-
| test.py:59 | ok | str_methods | ts.lower() |
25-
| test.py:61 | ok | str_methods | ts.replace(..) |
26-
| test.py:62 | ok | str_methods | "safe".replace(..) |
27-
| test.py:64 | ok | str_methods | ts.rjust(..) |
28-
| test.py:65 | ok | str_methods | ts.rstrip() |
29-
| test.py:66 | ok | str_methods | ts.strip() |
30-
| test.py:67 | ok | str_methods | ts.swapcase() |
31-
| test.py:68 | ok | str_methods | ts.title() |
32-
| test.py:69 | ok | str_methods | ts.upper() |
33-
| test.py:70 | ok | str_methods | ts.zfill(..) |
34-
| test.py:72 | ok | str_methods | ts.encode(..) |
35-
| test.py:73 | ok | str_methods | ts.encode(..).decode(..) |
36-
| test.py:75 | ok | str_methods | tb.decode(..) |
37-
| test.py:76 | ok | str_methods | tb.decode(..).encode(..) |
38-
| test.py:79 | ok | str_methods | ts.partition(..) |
39-
| test.py:80 | ok | str_methods | ts.rpartition(..) |
40-
| test.py:81 | ok | str_methods | ts.rsplit(..) |
41-
| test.py:82 | ok | str_methods | ts.split(..) |
42-
| test.py:83 | ok | str_methods | ts.splitlines() |
43-
| test.py:88 | ok | str_methods | "safe".replace(..) |
44-
| test.py:90 | fail | str_methods | ts.join(..) |
45-
| test.py:91 | fail | str_methods | ts.join(..) |
46-
| test.py:101 | fail | non_syntactic | meth() |
47-
| test.py:102 | fail | non_syntactic | _str(..) |
48-
| test.py:111 | ok | percent_fmt | BinaryExpr |
49-
| test.py:112 | ok | percent_fmt | BinaryExpr |
50-
| test.py:113 | fail | percent_fmt | BinaryExpr |
51-
| test.py:123 | fail | binary_decode_encode | base64.b64encode(..) |
52-
| test.py:124 | fail | binary_decode_encode | base64.b64decode(..) |
53-
| test.py:126 | fail | binary_decode_encode | base64.standard_b64encode(..) |
54-
| test.py:127 | fail | binary_decode_encode | base64.standard_b64decode(..) |
55-
| test.py:129 | fail | binary_decode_encode | base64.urlsafe_b64encode(..) |
56-
| test.py:130 | fail | binary_decode_encode | base64.urlsafe_b64decode(..) |
57-
| test.py:132 | fail | binary_decode_encode | base64.b32encode(..) |
58-
| test.py:133 | fail | binary_decode_encode | base64.b32decode(..) |
59-
| test.py:135 | fail | binary_decode_encode | base64.b16encode(..) |
60-
| test.py:136 | fail | binary_decode_encode | base64.b16decode(..) |
61-
| test.py:151 | fail | binary_decode_encode | base64.encodestring(..) |
62-
| test.py:152 | fail | binary_decode_encode | base64.decodestring(..) |
63-
| test.py:157 | fail | binary_decode_encode | quopri.encodestring(..) |
64-
| test.py:158 | fail | binary_decode_encode | quopri.decodestring(..) |
1+
| test.py:32 | ok | str_operations | ts |
2+
| test.py:33 | ok | str_operations | BinaryExpr |
3+
| test.py:34 | ok | str_operations | BinaryExpr |
4+
| test.py:35 | ok | str_operations | BinaryExpr |
5+
| test.py:36 | ok | str_operations | ts[Slice] |
6+
| test.py:37 | ok | str_operations | ts[Slice] |
7+
| test.py:38 | ok | str_operations | ts[Slice] |
8+
| test.py:39 | ok | str_operations | ts[0] |
9+
| test.py:40 | ok | str_operations | str(..) |
10+
| test.py:41 | ok | str_operations | bytes(..) |
11+
| test.py:42 | ok | str_operations | unicode(..) |
12+
| test.py:51 | ok | str_methods | ts.capitalize() |
13+
| test.py:52 | ok | str_methods | ts.casefold() |
14+
| test.py:53 | ok | str_methods | ts.center(..) |
15+
| test.py:54 | ok | str_methods | ts.expandtabs() |
16+
| test.py:56 | ok | str_methods | ts.format() |
17+
| test.py:57 | ok | str_methods | "{}".format(..) |
18+
| test.py:58 | ok | str_methods | "{unsafe}".format(..) |
19+
| test.py:60 | ok | str_methods | ts.format_map(..) |
20+
| test.py:61 | fail | str_methods | "{unsafe}".format_map(..) |
21+
| test.py:63 | ok | str_methods | ts.join(..) |
22+
| test.py:64 | fail | str_methods | "".join(..) |
23+
| test.py:66 | ok | str_methods | ts.ljust(..) |
24+
| test.py:67 | ok | str_methods | ts.lstrip() |
25+
| test.py:68 | ok | str_methods | ts.lower() |
26+
| test.py:70 | ok | str_methods | ts.replace(..) |
27+
| test.py:71 | ok | str_methods | "safe".replace(..) |
28+
| test.py:73 | ok | str_methods | ts.rjust(..) |
29+
| test.py:74 | ok | str_methods | ts.rstrip() |
30+
| test.py:75 | ok | str_methods | ts.strip() |
31+
| test.py:76 | ok | str_methods | ts.swapcase() |
32+
| test.py:77 | ok | str_methods | ts.title() |
33+
| test.py:78 | ok | str_methods | ts.upper() |
34+
| test.py:79 | ok | str_methods | ts.zfill(..) |
35+
| test.py:81 | ok | str_methods | ts.encode(..) |
36+
| test.py:82 | ok | str_methods | ts.encode(..).decode(..) |
37+
| test.py:84 | ok | str_methods | tb.decode(..) |
38+
| test.py:85 | ok | str_methods | tb.decode(..).encode(..) |
39+
| test.py:88 | ok | str_methods | ts.partition(..) |
40+
| test.py:89 | ok | str_methods | ts.rpartition(..) |
41+
| test.py:90 | ok | str_methods | ts.rsplit(..) |
42+
| test.py:91 | ok | str_methods | ts.split(..) |
43+
| test.py:92 | ok | str_methods | ts.splitlines() |
44+
| test.py:97 | ok | str_methods | "safe".replace(..) |
45+
| test.py:99 | fail | str_methods | ts.join(..) |
46+
| test.py:100 | fail | str_methods | ts.join(..) |
47+
| test.py:110 | fail | non_syntactic | meth() |
48+
| test.py:111 | fail | non_syntactic | _str(..) |
49+
| test.py:120 | ok | percent_fmt | BinaryExpr |
50+
| test.py:121 | ok | percent_fmt | BinaryExpr |
51+
| test.py:122 | fail | percent_fmt | BinaryExpr |
52+
| test.py:132 | fail | binary_decode_encode | base64.b64encode(..) |
53+
| test.py:133 | fail | binary_decode_encode | base64.b64decode(..) |
54+
| test.py:135 | fail | binary_decode_encode | base64.standard_b64encode(..) |
55+
| test.py:136 | fail | binary_decode_encode | base64.standard_b64decode(..) |
56+
| test.py:138 | fail | binary_decode_encode | base64.urlsafe_b64encode(..) |
57+
| test.py:139 | fail | binary_decode_encode | base64.urlsafe_b64decode(..) |
58+
| test.py:141 | fail | binary_decode_encode | base64.b32encode(..) |
59+
| test.py:142 | fail | binary_decode_encode | base64.b32decode(..) |
60+
| test.py:144 | fail | binary_decode_encode | base64.b16encode(..) |
61+
| test.py:145 | fail | binary_decode_encode | base64.b16decode(..) |
62+
| test.py:160 | fail | binary_decode_encode | base64.encodestring(..) |
63+
| test.py:161 | fail | binary_decode_encode | base64.decodestring(..) |
64+
| test.py:166 | fail | binary_decode_encode | quopri.encodestring(..) |
65+
| test.py:167 | fail | binary_decode_encode | quopri.decodestring(..) |

python/ql/test/experimental/dataflow/tainttracking/string/test.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import sys
2+
3+
if sys.version_info[0] == 3:
4+
unicode = str
5+
6+
17
TAINTED_STRING = "TAINTED_STRING"
28
TAINTED_BYTES = b"TAINTED_BYTES"
39

@@ -20,6 +26,8 @@ def ensure_not_tainted(*args):
2026
def str_operations():
2127
print("\n# str_operations")
2228
ts = TAINTED_STRING
29+
tb = TAINTED_BYTES
30+
2331
ensure_tainted(
2432
ts,
2533
ts + "foo",
@@ -30,7 +38,8 @@ def str_operations():
3038
ts[0:1000],
3139
ts[0],
3240
str(ts),
33-
bytes(ts),
41+
bytes(tb),
42+
unicode(ts),
3443
)
3544

3645

0 commit comments

Comments
 (0)