Skip to content

Commit f85ee38

Browse files
Add instance taint steps for requests
1 parent 88e3227 commit f85ee38

File tree

2 files changed

+104
-3
lines changed

2 files changed

+104
-3
lines changed

python/ql/lib/semmle/python/frameworks/Pyramid.qll

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ private import semmle.python.Concepts
1111
private import semmle.python.ApiGraphs
1212
private import semmle.python.dataflow.new.FlowSummary
1313
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
14+
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
1415
private import semmle.python.frameworks.data.ModelsAsData
1516

1617
/**
@@ -84,4 +85,47 @@ module Pyramid {
8485
DataFlow::Node getViewArg() { result = [this.getArg(0), this.getArgByName("view")] }
8586
}
8687
}
88+
89+
module Request {
90+
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
91+
92+
/** Gets a reference to an instance of `pyramid.request.Request`. */
93+
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
94+
t.start() and
95+
result instanceof InstanceSource
96+
or
97+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
98+
}
99+
100+
/** Gets a reference to an instance of `pyramid.request.Request`. */
101+
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
102+
103+
private class RequestParameter extends InstanceSource, DataFlow::ParameterNode {
104+
RequestParameter() { this.getParameter() = any(View::ViewCallable vc).getRequestParameter() }
105+
}
106+
107+
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
108+
InstanceTaintSteps() { this = "pyramid.request.Request" }
109+
110+
override DataFlow::Node getInstance() { result = instance() }
111+
112+
override string getAttributeName() {
113+
result in [
114+
"accept", "accept_charset", "accept_encoding", "accept_language", "application_url",
115+
"as_bytes", "authorization", "body", "body_file", "body_file_raw", "body_file_seekable",
116+
"cache_control", "client_addr", "content_type", "cookies", "domain", "headers", "host",
117+
"host_port", "host_url", "GET", "if_match", "if_none_match", "if_range",
118+
"if_none_match", "json", "json_body", "params", "path", "path_info", "path_qs",
119+
"path_url", "POST", "pragma", "query_string", "range", "referer", "referrer", "text",
120+
"url", "urlargs", "urlvars", "user_agent"
121+
]
122+
}
123+
124+
override string getMethodName() {
125+
result in ["as_bytes", "copy", "copy_body", "copy_get", "path_info_peek", "path_info_pop"]
126+
}
127+
128+
override string getAsyncMethodName() { none() }
129+
}
130+
}
87131
}

python/ql/test/library-tests/frameworks/pyramid/pyramid_test.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,66 @@
44
@view_config(route_name="test1")
55
def test1(request):
66
ensure_tainted(
7-
request, # $ tainted
8-
request.body, # $ MISSING:tainted
9-
request.GET['a'] # $ MISSING:tainted
7+
request, # $ tainted
8+
9+
request.accept, # $ tainted
10+
request.accept_charset, # $ tainted
11+
request.accept_encoding, # $ tainted
12+
request.accept_language, # $ tainted
13+
request.authorization, # $ tainted
14+
request.cache_control, # $ tainted
15+
request.client_addr, # $ tainted
16+
request.content_type, # $ tainted
17+
request.domain, # $ tainted
18+
request.host, # $ tainted
19+
request.host_port, # $ tainted
20+
request.host_url, # $ tainted
21+
request.if_match, # $ tainted
22+
request.if_none_match, # $ tainted
23+
request.if_range, # $ tainted
24+
request.pragma, # $ tainted
25+
request.range, # $ tainted
26+
request.referer, # $ tainted
27+
request.referrer, # $ tainted
28+
request.user_agent, # $ tainted
29+
30+
request.as_bytes, # $ tainted
31+
32+
request.body, # $ tainted
33+
request.body_file, # $ tainted
34+
request.body_file_raw, # $ tainted
35+
request.body_file_seekable,# $ tainted
36+
request.body_file.read(), # $ MISSING:tainted
37+
38+
request.json, # $ tainted
39+
request.json_body, # $ tainted
40+
request.json['a']['b'][0]['c'], # $ tainted
41+
42+
request.text, # $ tainted
43+
44+
request.path, # $ tainted
45+
request.path_info, # $ tainted
46+
request.path_info_peek(), # $ tainted
47+
request.path_info_pop(), # $ tainted
48+
request.path_qs, # $ tainted
49+
request.path_url, # $ tainted
50+
request.query_string, # $ tainted
51+
52+
request.url, # $ tainted
53+
request.urlargs, # $ tainted
54+
request.urlvars, # $ tainted
55+
56+
request.GET['a'], # $ tainted
57+
request.POST['b'], # $ tainted
58+
request.cookies['c'], # $ tainted
59+
request.params['d'], # $ tainted
60+
request.headers['X-My-Header'], # $ tainted
61+
request.GET.values(), # $ tainted
62+
63+
request.copy(), # $ tainted
64+
request.copy_body(), # $ tainted
65+
request.copy_get(), # $ tainted
66+
request.copy().GET['a'] # $ MISSING:tainted
1067
)
1168

1269
def test2(request):

0 commit comments

Comments
 (0)