Skip to content

Commit 49e5f8a

Browse files
Add tests for instances of the header write concept
1 parent f3b27d6 commit 49e5f8a

File tree

5 files changed

+141
-2
lines changed

5 files changed

+141
-2
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
source
2+
| flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember |
3+
| wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ |
4+
| wsgiref_tests.py:12:15:12:21 | ControlFlowNode for environ |
5+
sink
6+
| flask_tests.py:12:17:12:28 | ControlFlowNode for Str |
7+
| flask_tests.py:13:17:13:26 | ControlFlowNode for rfs_header |
8+
| flask_tests.py:22:22:22:33 | ControlFlowNode for Str |
9+
| flask_tests.py:23:22:23:31 | ControlFlowNode for rfs_header |
10+
| flask_tests.py:31:22:31:33 | ControlFlowNode for Str |
11+
| flask_tests.py:32:22:32:31 | ControlFlowNode for rfs_header |
12+
| flask_tests.py:41:10:41:21 | ControlFlowNode for Str |
13+
| flask_tests.py:43:10:43:19 | ControlFlowNode for rfs_header |
14+
| flask_tests.py:49:30:49:41 | ControlFlowNode for Str |
15+
| flask_tests.py:49:72:49:97 | ControlFlowNode for Subscript |
16+
| flask_tests.py:54:41:54:66 | ControlFlowNode for Subscript |
17+
| flask_tests.py:60:36:60:61 | ControlFlowNode for Subscript |
18+
| flask_tests.py:66:36:66:63 | ControlFlowNode for Attribute() |
19+
| flask_tests.py:74:17:74:26 | ControlFlowNode for rfs_header |
20+
| flask_tests.py:75:24:75:33 | ControlFlowNode for rfs_header |
21+
| flask_tests.py:76:17:76:26 | ControlFlowNode for rfs_header |
22+
| flask_tests.py:77:24:77:33 | ControlFlowNode for rfs_header |
23+
| flask_tests.py:78:25:78:34 | ControlFlowNode for rfs_header |
24+
| flask_tests.py:79:13:79:22 | ControlFlowNode for rfs_header |
25+
| flask_tests.py:80:11:80:20 | ControlFlowNode for rfs_header |
26+
| flask_tests.py:82:12:82:21 | ControlFlowNode for rfs_header |
27+
| flask_tests.py:85:11:85:20 | ControlFlowNode for rfs_header |
28+
| flask_tests.py:86:12:86:21 | ControlFlowNode for rfs_header |
29+
| wsgiref_tests.py:8:17:8:22 | ControlFlowNode for h_name |
30+
| wsgiref_tests.py:8:25:8:29 | ControlFlowNode for Str |
31+
| wsgiref_tests.py:8:34:8:39 | ControlFlowNode for Str |
32+
| wsgiref_tests.py:8:42:8:46 | ControlFlowNode for h_val |
33+
| wsgiref_tests.py:16:25:16:30 | ControlFlowNode for h_name |
34+
| wsgiref_tests.py:16:33:16:37 | ControlFlowNode for Str |
35+
| wsgiref_tests.py:16:42:16:47 | ControlFlowNode for Str |
36+
| wsgiref_tests.py:16:50:16:54 | ControlFlowNode for h_val |
37+
| wsgiref_tests.py:17:24:17:29 | ControlFlowNode for h_name |
38+
| wsgiref_tests.py:17:32:17:36 | ControlFlowNode for h_val |
39+
| wsgiref_tests.py:18:24:18:29 | ControlFlowNode for h_name |
40+
| wsgiref_tests.py:18:32:18:36 | ControlFlowNode for h_val |
41+
| wsgiref_tests.py:19:25:19:30 | ControlFlowNode for h_name |
42+
| wsgiref_tests.py:19:33:19:37 | ControlFlowNode for h_val |
43+
| wsgiref_tests.py:20:13:20:18 | ControlFlowNode for h_name |
44+
| wsgiref_tests.py:20:23:20:27 | ControlFlowNode for h_val |
45+
headerWrite
46+
| flask_tests.py:12:5:12:41 | ControlFlowNode for Attribute() | flask_tests.py:12:17:12:28 | ControlFlowNode for Str | flask_tests.py:12:31:12:40 | ControlFlowNode for rfs_header | true | false |
47+
| flask_tests.py:13:5:13:42 | ControlFlowNode for Attribute() | flask_tests.py:13:17:13:26 | ControlFlowNode for rfs_header | flask_tests.py:13:29:13:41 | ControlFlowNode for Str | true | false |
48+
| flask_tests.py:22:5:22:34 | ControlFlowNode for Subscript | flask_tests.py:22:22:22:33 | ControlFlowNode for Str | flask_tests.py:22:38:22:47 | ControlFlowNode for rfs_header | true | false |
49+
| flask_tests.py:23:5:23:32 | ControlFlowNode for Subscript | flask_tests.py:23:22:23:31 | ControlFlowNode for rfs_header | flask_tests.py:23:36:23:48 | ControlFlowNode for Str | true | false |
50+
| flask_tests.py:31:5:31:34 | ControlFlowNode for Subscript | flask_tests.py:31:22:31:33 | ControlFlowNode for Str | flask_tests.py:31:38:31:47 | ControlFlowNode for rfs_header | true | false |
51+
| flask_tests.py:32:5:32:32 | ControlFlowNode for Subscript | flask_tests.py:32:22:32:31 | ControlFlowNode for rfs_header | flask_tests.py:32:36:32:48 | ControlFlowNode for Str | true | false |
52+
| flask_tests.py:40:5:41:35 | ControlFlowNode for Attribute() | flask_tests.py:41:10:41:21 | ControlFlowNode for Str | flask_tests.py:41:24:41:33 | ControlFlowNode for rfs_header | true | false |
53+
| flask_tests.py:42:5:43:36 | ControlFlowNode for Attribute() | flask_tests.py:43:10:43:19 | ControlFlowNode for rfs_header | flask_tests.py:43:22:43:34 | ControlFlowNode for Str | true | false |
54+
| flask_tests.py:49:12:49:114 | ControlFlowNode for Response() | flask_tests.py:49:30:49:41 | ControlFlowNode for Str | flask_tests.py:49:44:49:69 | ControlFlowNode for Subscript | true | false |
55+
| flask_tests.py:49:12:49:114 | ControlFlowNode for Response() | flask_tests.py:49:30:49:41 | ControlFlowNode for Str | flask_tests.py:49:100:49:112 | ControlFlowNode for Str | true | false |
56+
| flask_tests.py:49:12:49:114 | ControlFlowNode for Response() | flask_tests.py:49:72:49:97 | ControlFlowNode for Subscript | flask_tests.py:49:44:49:69 | ControlFlowNode for Subscript | true | false |
57+
| flask_tests.py:49:12:49:114 | ControlFlowNode for Response() | flask_tests.py:49:72:49:97 | ControlFlowNode for Subscript | flask_tests.py:49:100:49:112 | ControlFlowNode for Str | true | false |
58+
| flask_tests.py:54:12:54:83 | ControlFlowNode for make_response() | flask_tests.py:54:41:54:66 | ControlFlowNode for Subscript | flask_tests.py:54:69:54:81 | ControlFlowNode for Str | true | false |
59+
| flask_tests.py:60:12:60:78 | ControlFlowNode for make_response() | flask_tests.py:60:36:60:61 | ControlFlowNode for Subscript | flask_tests.py:60:64:60:76 | ControlFlowNode for Str | true | false |
60+
| flask_tests.py:66:12:66:80 | ControlFlowNode for make_response() | flask_tests.py:66:36:66:63 | ControlFlowNode for Attribute() | flask_tests.py:66:66:66:78 | ControlFlowNode for Str | true | false |
61+
| flask_tests.py:74:5:74:42 | ControlFlowNode for Attribute() | flask_tests.py:74:17:74:26 | ControlFlowNode for rfs_header | flask_tests.py:74:29:74:41 | ControlFlowNode for Str | true | false |
62+
| flask_tests.py:75:5:75:49 | ControlFlowNode for Attribute() | flask_tests.py:75:24:75:33 | ControlFlowNode for rfs_header | flask_tests.py:75:36:75:48 | ControlFlowNode for Str | true | false |
63+
| flask_tests.py:76:5:76:42 | ControlFlowNode for Attribute() | flask_tests.py:76:17:76:26 | ControlFlowNode for rfs_header | flask_tests.py:76:29:76:41 | ControlFlowNode for Str | true | false |
64+
| flask_tests.py:77:5:77:49 | ControlFlowNode for Attribute() | flask_tests.py:77:24:77:33 | ControlFlowNode for rfs_header | flask_tests.py:77:36:77:48 | ControlFlowNode for Str | true | false |
65+
| flask_tests.py:78:5:78:50 | ControlFlowNode for Attribute() | flask_tests.py:78:25:78:34 | ControlFlowNode for rfs_header | flask_tests.py:78:37:78:49 | ControlFlowNode for Str | true | false |
66+
| flask_tests.py:79:5:79:23 | ControlFlowNode for Subscript | flask_tests.py:79:13:79:22 | ControlFlowNode for rfs_header | flask_tests.py:79:27:79:39 | ControlFlowNode for Str | true | false |
67+
| flask_tests.py:81:5:81:22 | ControlFlowNode for Attribute() | flask_tests.py:80:11:80:20 | ControlFlowNode for rfs_header | flask_tests.py:80:23:80:35 | ControlFlowNode for Str | true | false |
68+
| flask_tests.py:83:5:83:22 | ControlFlowNode for Attribute() | flask_tests.py:82:12:82:21 | ControlFlowNode for rfs_header | flask_tests.py:82:24:82:36 | ControlFlowNode for Str | true | false |
69+
| flask_tests.py:87:13:87:35 | ControlFlowNode for make_response() | flask_tests.py:85:11:85:20 | ControlFlowNode for rfs_header | flask_tests.py:85:23:85:35 | ControlFlowNode for Str | true | false |
70+
| flask_tests.py:88:13:88:35 | ControlFlowNode for make_response() | flask_tests.py:86:12:86:21 | ControlFlowNode for rfs_header | flask_tests.py:86:24:86:36 | ControlFlowNode for Str | true | false |
71+
| wsgiref_tests.py:9:5:9:35 | ControlFlowNode for start_response() | wsgiref_tests.py:8:17:8:22 | ControlFlowNode for h_name | wsgiref_tests.py:8:25:8:29 | ControlFlowNode for Str | true | true |
72+
| wsgiref_tests.py:9:5:9:35 | ControlFlowNode for start_response() | wsgiref_tests.py:8:17:8:22 | ControlFlowNode for h_name | wsgiref_tests.py:8:42:8:46 | ControlFlowNode for h_val | true | true |
73+
| wsgiref_tests.py:9:5:9:35 | ControlFlowNode for start_response() | wsgiref_tests.py:8:34:8:39 | ControlFlowNode for Str | wsgiref_tests.py:8:25:8:29 | ControlFlowNode for Str | true | true |
74+
| wsgiref_tests.py:9:5:9:35 | ControlFlowNode for start_response() | wsgiref_tests.py:8:34:8:39 | ControlFlowNode for Str | wsgiref_tests.py:8:42:8:46 | ControlFlowNode for h_val | true | true |
75+
| wsgiref_tests.py:16:15:16:57 | ControlFlowNode for Headers() | wsgiref_tests.py:16:25:16:30 | ControlFlowNode for h_name | wsgiref_tests.py:16:33:16:37 | ControlFlowNode for Str | true | true |
76+
| wsgiref_tests.py:16:15:16:57 | ControlFlowNode for Headers() | wsgiref_tests.py:16:25:16:30 | ControlFlowNode for h_name | wsgiref_tests.py:16:50:16:54 | ControlFlowNode for h_val | true | true |
77+
| wsgiref_tests.py:16:15:16:57 | ControlFlowNode for Headers() | wsgiref_tests.py:16:42:16:47 | ControlFlowNode for Str | wsgiref_tests.py:16:33:16:37 | ControlFlowNode for Str | true | true |
78+
| wsgiref_tests.py:16:15:16:57 | ControlFlowNode for Headers() | wsgiref_tests.py:16:42:16:47 | ControlFlowNode for Str | wsgiref_tests.py:16:50:16:54 | ControlFlowNode for h_val | true | true |
79+
| wsgiref_tests.py:17:5:17:37 | ControlFlowNode for Attribute() | wsgiref_tests.py:17:24:17:29 | ControlFlowNode for h_name | wsgiref_tests.py:17:32:17:36 | ControlFlowNode for h_val | true | true |
80+
| wsgiref_tests.py:18:5:18:37 | ControlFlowNode for Attribute() | wsgiref_tests.py:18:24:18:29 | ControlFlowNode for h_name | wsgiref_tests.py:18:32:18:36 | ControlFlowNode for h_val | true | true |
81+
| wsgiref_tests.py:19:5:19:38 | ControlFlowNode for Attribute() | wsgiref_tests.py:19:25:19:30 | ControlFlowNode for h_name | wsgiref_tests.py:19:33:19:37 | ControlFlowNode for h_val | true | true |
82+
| wsgiref_tests.py:20:5:20:19 | ControlFlowNode for Subscript | wsgiref_tests.py:20:13:20:18 | ControlFlowNode for h_name | wsgiref_tests.py:20:23:20:27 | ControlFlowNode for h_val | true | true |
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import python
2+
import semmle.python.security.dataflow.HttpHeaderInjectionCustomizations
3+
import semmle.python.dataflow.new.DataFlow
4+
import semmle.python.Concepts
5+
6+
query predicate source(HttpHeaderInjection::Source src) {
7+
src.getLocation().getFile().getBaseName() in ["wsgiref_tests.py", "flask_tests.py"]
8+
}
9+
10+
query predicate sink(HttpHeaderInjection::Sink sink) { any() }
11+
12+
query predicate headerWrite(
13+
Http::Server::ResponseHeaderWrite write, DataFlow::Node name, DataFlow::Node val,
14+
boolean nameVuln, boolean valVuln
15+
) {
16+
name = write.getNameArg() and
17+
val = write.getValueArg() and
18+
(if write.nameAllowsNewline() then nameVuln = true else nameVuln = false) and
19+
(if write.valueAllowsNewline() then valVuln = true else valVuln = false)
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
source
2+
| wsgiref_tests.py:5:14:5:20 | ControlFlowNode for environ |
3+
| wsgiref_tests.py:13:15:13:21 | ControlFlowNode for environ |
4+
sink
5+
headerWrite
6+
| wsgiref_tests.py:10:5:10:35 | ControlFlowNode for start_response() | wsgiref_tests.py:9:17:9:22 | ControlFlowNode for h_name | wsgiref_tests.py:9:25:9:29 | ControlFlowNode for Str | false | false |
7+
| wsgiref_tests.py:10:5:10:35 | ControlFlowNode for start_response() | wsgiref_tests.py:9:17:9:22 | ControlFlowNode for h_name | wsgiref_tests.py:9:42:9:46 | ControlFlowNode for h_val | false | false |
8+
| wsgiref_tests.py:10:5:10:35 | ControlFlowNode for start_response() | wsgiref_tests.py:9:34:9:39 | ControlFlowNode for Str | wsgiref_tests.py:9:25:9:29 | ControlFlowNode for Str | false | false |
9+
| wsgiref_tests.py:10:5:10:35 | ControlFlowNode for start_response() | wsgiref_tests.py:9:34:9:39 | ControlFlowNode for Str | wsgiref_tests.py:9:42:9:46 | ControlFlowNode for h_val | false | false |
10+
| wsgiref_tests.py:17:15:17:57 | ControlFlowNode for Headers() | wsgiref_tests.py:17:25:17:30 | ControlFlowNode for h_name | wsgiref_tests.py:17:33:17:37 | ControlFlowNode for Str | false | false |
11+
| wsgiref_tests.py:17:15:17:57 | ControlFlowNode for Headers() | wsgiref_tests.py:17:25:17:30 | ControlFlowNode for h_name | wsgiref_tests.py:17:50:17:54 | ControlFlowNode for h_val | false | false |
12+
| wsgiref_tests.py:17:15:17:57 | ControlFlowNode for Headers() | wsgiref_tests.py:17:42:17:47 | ControlFlowNode for Str | wsgiref_tests.py:17:33:17:37 | ControlFlowNode for Str | false | false |
13+
| wsgiref_tests.py:17:15:17:57 | ControlFlowNode for Headers() | wsgiref_tests.py:17:42:17:47 | ControlFlowNode for Str | wsgiref_tests.py:17:50:17:54 | ControlFlowNode for h_val | false | false |
14+
| wsgiref_tests.py:18:5:18:37 | ControlFlowNode for Attribute() | wsgiref_tests.py:18:24:18:29 | ControlFlowNode for h_name | wsgiref_tests.py:18:32:18:36 | ControlFlowNode for h_val | false | false |
15+
| wsgiref_tests.py:19:5:19:37 | ControlFlowNode for Attribute() | wsgiref_tests.py:19:24:19:29 | ControlFlowNode for h_name | wsgiref_tests.py:19:32:19:36 | ControlFlowNode for h_val | false | false |
16+
| wsgiref_tests.py:20:5:20:38 | ControlFlowNode for Attribute() | wsgiref_tests.py:20:25:20:30 | ControlFlowNode for h_name | wsgiref_tests.py:20:33:20:37 | ControlFlowNode for h_val | false | false |
17+
| wsgiref_tests.py:21:5:21:19 | ControlFlowNode for Subscript | wsgiref_tests.py:21:13:21:18 | ControlFlowNode for h_name | wsgiref_tests.py:21:23:21:27 | ControlFlowNode for h_val | false | false |
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import python
2+
import semmle.python.security.dataflow.HttpHeaderInjectionCustomizations
3+
import semmle.python.dataflow.new.DataFlow
4+
import semmle.python.Concepts
5+
6+
query predicate source(HttpHeaderInjection::Source src) {
7+
src.getLocation().getFile().getBaseName() in ["wsgiref_tests.py", "flask_tests.py"]
8+
}
9+
10+
query predicate sink(HttpHeaderInjection::Sink sink) { any() }
11+
12+
query predicate headerWrite(
13+
Http::Server::ResponseHeaderWrite write, DataFlow::Node name, DataFlow::Node val,
14+
boolean nameVuln, boolean valVuln
15+
) {
16+
name = write.getNameArg() and
17+
val = write.getValueArg() and
18+
(if write.nameAllowsNewline() then nameVuln = true else nameVuln = false) and
19+
(if write.valueAllowsNewline() then valVuln = true else valVuln = false)
20+
}

python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2/wsgiref_tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ def test_app2(environ, start_response):
2323
return [b"Hello"]
2424

2525
def main1():
26-
with make_server('', 8000, validate(test_app)) as httpd:
26+
with make_server('', 8000, validator(test_app)) as httpd:
2727
print("Serving on port 8000...")
2828
httpd.serve_forever()
2929

3030
def main2():
31-
with make_server('', 8000, validate(test_app2)) as httpd:
31+
with make_server('', 8000, validator(test_app2)) as httpd:
3232
print("Serving on port 8000...")
3333
httpd.serve_forever()

0 commit comments

Comments
 (0)