Skip to content

Commit

Permalink
Add tests for instances of the header write concept
Browse files Browse the repository at this point in the history
  • Loading branch information
joefarebrother committed Apr 8, 2024
1 parent cdb2260 commit 247cfc5
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
source
| flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember |
| wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ |
| wsgiref_tests.py:12:15:12:21 | ControlFlowNode for environ |
sink
| flask_tests.py:12:17:12:28 | ControlFlowNode for Str |
| flask_tests.py:13:17:13:26 | ControlFlowNode for rfs_header |
| flask_tests.py:22:22:22:33 | ControlFlowNode for Str |
| flask_tests.py:23:22:23:31 | ControlFlowNode for rfs_header |
| flask_tests.py:31:22:31:33 | ControlFlowNode for Str |
| flask_tests.py:32:22:32:31 | ControlFlowNode for rfs_header |
| flask_tests.py:41:10:41:21 | ControlFlowNode for Str |
| flask_tests.py:43:10:43:19 | ControlFlowNode for rfs_header |
| flask_tests.py:49:30:49:41 | ControlFlowNode for Str |
| flask_tests.py:49:72:49:97 | ControlFlowNode for Subscript |
| flask_tests.py:54:41:54:66 | ControlFlowNode for Subscript |
| flask_tests.py:60:36:60:61 | ControlFlowNode for Subscript |
| flask_tests.py:66:36:66:63 | ControlFlowNode for Attribute() |
| flask_tests.py:74:17:74:26 | ControlFlowNode for rfs_header |
| flask_tests.py:75:24:75:33 | ControlFlowNode for rfs_header |
| flask_tests.py:76:17:76:26 | ControlFlowNode for rfs_header |
| flask_tests.py:77:24:77:33 | ControlFlowNode for rfs_header |
| flask_tests.py:78:25:78:34 | ControlFlowNode for rfs_header |
| flask_tests.py:79:13:79:22 | ControlFlowNode for rfs_header |
| flask_tests.py:80:11:80:20 | ControlFlowNode for rfs_header |
| flask_tests.py:82:12:82:21 | ControlFlowNode for rfs_header |
| flask_tests.py:85:11:85:20 | ControlFlowNode for rfs_header |
| flask_tests.py:86:12:86:21 | ControlFlowNode for rfs_header |
| wsgiref_tests.py:8:17:8:22 | ControlFlowNode for h_name |
| wsgiref_tests.py:8:25:8:29 | ControlFlowNode for Str |
| wsgiref_tests.py:8:34:8:39 | ControlFlowNode for Str |
| wsgiref_tests.py:8:42:8:46 | ControlFlowNode for h_val |
| wsgiref_tests.py:16:25:16:30 | ControlFlowNode for h_name |
| wsgiref_tests.py:16:33:16:37 | ControlFlowNode for Str |
| wsgiref_tests.py:16:42:16:47 | ControlFlowNode for Str |
| wsgiref_tests.py:16:50:16:54 | ControlFlowNode for h_val |
| wsgiref_tests.py:17:24:17:29 | ControlFlowNode for h_name |
| wsgiref_tests.py:17:32:17:36 | ControlFlowNode for h_val |
| wsgiref_tests.py:18:24:18:29 | ControlFlowNode for h_name |
| wsgiref_tests.py:18:32:18:36 | ControlFlowNode for h_val |
| wsgiref_tests.py:19:25:19:30 | ControlFlowNode for h_name |
| wsgiref_tests.py:19:33:19:37 | ControlFlowNode for h_val |
| wsgiref_tests.py:20:13:20:18 | ControlFlowNode for h_name |
| wsgiref_tests.py:20:23:20:27 | ControlFlowNode for h_val |
headerWrite
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import python
import semmle.python.security.dataflow.HttpHeaderInjectionCustomizations
import semmle.python.dataflow.new.DataFlow
import semmle.python.Concepts

query predicate source(HttpHeaderInjection::Source src) {
src.getLocation().getFile().getBaseName() in ["wsgiref_tests.py", "flask_tests.py"]
}

query predicate sink(HttpHeaderInjection::Sink sink) { any() }

query predicate headerWrite(
Http::Server::ResponseHeaderWrite write, DataFlow::Node name, DataFlow::Node val,
boolean nameVuln, boolean valVuln
) {
name = write.getNameArg() and
val = write.getValueArg() and
(if write.nameAllowsNewline() then nameVuln = true else nameVuln = false) and
(if write.valueAllowsNewline() then valVuln = true else valVuln = false)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
source
| wsgiref_tests.py:5:14:5:20 | ControlFlowNode for environ |
| wsgiref_tests.py:13:15:13:21 | ControlFlowNode for environ |
sink
headerWrite
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import python
import semmle.python.security.dataflow.HttpHeaderInjectionCustomizations
import semmle.python.dataflow.new.DataFlow
import semmle.python.Concepts

query predicate source(HttpHeaderInjection::Source src) {
src.getLocation().getFile().getBaseName() in ["wsgiref_tests.py", "flask_tests.py"]
}

query predicate sink(HttpHeaderInjection::Sink sink) { any() }

query predicate headerWrite(
Http::Server::ResponseHeaderWrite write, DataFlow::Node name, DataFlow::Node val,
boolean nameVuln, boolean valVuln
) {
name = write.getNameArg() and
val = write.getValueArg() and
(if write.nameAllowsNewline() then nameVuln = true else nameVuln = false) and
(if write.valueAllowsNewline() then valVuln = true else valVuln = false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ def test_app2(environ, start_response):
return [b"Hello"]

def main1():
with make_server('', 8000, validate(test_app)) as httpd:
with make_server('', 8000, validator(test_app)) as httpd:
print("Serving on port 8000...")
httpd.serve_forever()

def main2():
with make_server('', 8000, validate(test_app2)) as httpd:
with make_server('', 8000, validator(test_app2)) as httpd:
print("Serving on port 8000...")
httpd.serve_forever()

0 comments on commit 247cfc5

Please sign in to comment.