Skip to content

Commit f209e3a

Browse files
committed
Python: Updated PathInjection tests to use inline test expectations
1 parent 7670a2b commit f209e3a

File tree

8 files changed

+49
-54
lines changed

8 files changed

+49
-54
lines changed

python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected

Lines changed: 0 additions & 2 deletions
This file was deleted.

python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.ql

Lines changed: 0 additions & 4 deletions
This file was deleted.

python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
#select
2+
| flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
3+
| path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
4+
| path_injection.py:21:14:21:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:21:14:21:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
5+
| path_injection.py:31:14:31:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:31:14:31:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
6+
| path_injection.py:48:14:48:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:48:14:48:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
7+
| path_injection.py:65:14:65:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:65:14:65:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
8+
| path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
9+
| path_injection.py:94:14:94:17 | ControlFlowNode for path | path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | path_injection.py:94:14:94:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | user-provided value |
10+
| path_injection.py:102:14:102:17 | ControlFlowNode for path | path_injection.py:98:20:98:22 | ControlFlowNode for foo | path_injection.py:102:14:102:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:98:20:98:22 | ControlFlowNode for foo | user-provided value |
11+
| path_injection.py:113:14:113:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:113:14:113:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
12+
| path_injection.py:124:14:124:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:124:14:124:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
13+
| path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
14+
| path_injection.py:142:14:142:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:142:14:142:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
15+
| path_injection.py:152:18:152:21 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:152:18:152:21 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
16+
| pathlib_use.py:14:5:14:5 | ControlFlowNode for p | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:14:5:14:5 | ControlFlowNode for p | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
17+
| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
18+
| test.py:19:10:19:10 | ControlFlowNode for x | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:19:10:19:10 | ControlFlowNode for x | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
19+
| test.py:26:10:26:10 | ControlFlowNode for y | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:26:10:26:10 | ControlFlowNode for y | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
20+
| test.py:33:14:33:14 | ControlFlowNode for x | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:33:14:33:14 | ControlFlowNode for x | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
21+
| test.py:49:14:49:14 | ControlFlowNode for y | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:49:14:49:14 | ControlFlowNode for y | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
122
edges
223
| flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:1:26:1:32 | ControlFlowNode for request | provenance | |
324
| flask_path_injection.py:1:26:1:32 | ControlFlowNode for request | flask_path_injection.py:19:15:19:21 | ControlFlowNode for request | provenance | |
@@ -252,24 +273,3 @@ nodes
252273
subpaths
253274
| test.py:25:19:25:19 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | test.py:25:9:25:20 | ControlFlowNode for normalize() |
254275
| test.py:48:23:48:23 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | test.py:48:13:48:24 | ControlFlowNode for normalize() |
255-
#select
256-
| flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
257-
| path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
258-
| path_injection.py:21:14:21:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:21:14:21:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
259-
| path_injection.py:31:14:31:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:31:14:31:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
260-
| path_injection.py:48:14:48:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:48:14:48:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
261-
| path_injection.py:65:14:65:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:65:14:65:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
262-
| path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
263-
| path_injection.py:94:14:94:17 | ControlFlowNode for path | path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | path_injection.py:94:14:94:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | user-provided value |
264-
| path_injection.py:102:14:102:17 | ControlFlowNode for path | path_injection.py:98:20:98:22 | ControlFlowNode for foo | path_injection.py:102:14:102:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:98:20:98:22 | ControlFlowNode for foo | user-provided value |
265-
| path_injection.py:113:14:113:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:113:14:113:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
266-
| path_injection.py:124:14:124:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:124:14:124:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
267-
| path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
268-
| path_injection.py:142:14:142:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:142:14:142:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
269-
| path_injection.py:152:18:152:21 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:152:18:152:21 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
270-
| pathlib_use.py:14:5:14:5 | ControlFlowNode for p | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:14:5:14:5 | ControlFlowNode for p | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
271-
| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
272-
| test.py:19:10:19:10 | ControlFlowNode for x | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:19:10:19:10 | ControlFlowNode for x | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
273-
| test.py:26:10:26:10 | ControlFlowNode for y | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:26:10:26:10 | ControlFlowNode for y | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
274-
| test.py:33:14:33:14 | ControlFlowNode for x | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:33:14:33:14 | ControlFlowNode for x | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
275-
| test.py:49:14:49:14 | ControlFlowNode for y | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:49:14:49:14 | ControlFlowNode for y | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value |
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
Security/CWE-022/PathInjection.ql
1+
query: Security/CWE-022/PathInjection.ql
2+
postprocess: utils/test/InlineExpectationsTestQuery.ql

python/ql/test/query-tests/Security/CWE-022-PathInjection/flask_path_injection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from flask import Flask, request, send_from_directory
1+
from flask import Flask, request, send_from_directory # $Source
22
app = Flask(__name__)
33

44

@@ -18,4 +18,4 @@ def download_file():
1818
def download_file():
1919
dirname = request.args.get('dirname', '')
2020
filename = request.args.get('filename', '')
21-
return send_from_directory(dirname, filename) # $result=BAD result=OK(filename)
21+
return send_from_directory(dirname, filename) # $ Alert

python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22

3-
from flask import Flask, request
3+
from flask import Flask, request # $ Source
44
app = Flask(__name__)
55

66

@@ -10,15 +10,15 @@
1010
@app.route("/path1")
1111
def path_injection():
1212
filename = request.args.get('filename', '')
13-
f = open(os.path.join(STATIC_DIR, filename)) # $result=BAD
13+
f = open(os.path.join(STATIC_DIR, filename)) # $ Alert
1414

1515

1616
@app.route("/path2")
1717
def path_injection():
1818
# Normalized, but not checked
1919
filename = request.args.get('filename', '')
2020
npath = os.path.normpath(os.path.join(STATIC_DIR, filename))
21-
f = open(npath) # $result=BAD
21+
f = open(npath) # $ Alert
2222

2323

2424
@app.route("/path3")
@@ -28,7 +28,7 @@ def unsafe_path_normpath():
2828
npath = os.path.normpath(os.path.join(STATIC_DIR, filename))
2929
if npath.startswith(STATIC_DIR):
3030
pass
31-
f = open(npath) # $result=BAD
31+
f = open(npath) # $ Alert
3232

3333

3434
@app.route("/path4")
@@ -45,7 +45,7 @@ def unsafe_path_realpath():
4545
# Normalized (by `realpath` that also follows symlinks), but not checked properly
4646
filename = request.args.get('filename', '')
4747
npath = os.path.realpath(os.path.join(STATIC_DIR, filename))
48-
f = open(npath) # $result=BAD
48+
f = open(npath) # $ Alert
4949

5050

5151
@app.route("/path6")
@@ -62,7 +62,7 @@ def unsafe_path_abspath():
6262
# Normalized (by `abspath`), but not checked properly
6363
filename = request.args.get('filename', '')
6464
npath = os.path.abspath(os.path.join(STATIC_DIR, filename))
65-
f = open(npath) # $result=BAD
65+
f = open(npath) # $ Alert
6666

6767

6868
@app.route("/path7")
@@ -84,22 +84,22 @@ def safe_path_abspath_tricky():
8484
filename = request.args.get('filename', '')
8585
possibly_unsafe_path = os.path.join(STATIC_DIR, filename)
8686
if os.path.abspath(possibly_unsafe_path).startswith(STATIC_DIR):
87-
f = open(possibly_unsafe_path) # $SPURIOUS: result=BAD
87+
f = open(possibly_unsafe_path) # $ SPURIOUS: Alert
8888

8989

9090
@app.route("/int-only/<int:foo_id>")
91-
def flask_int_only(foo_id):
91+
def flask_int_only(foo_id): # $ SPURIOUS: Source
9292
# This is OK, since the flask routing ensures that `foo_id` MUST be an integer.
9393
path = os.path.join(STATIC_DIR, foo_id)
94-
f = open(path) # $spurious: result=BAD
94+
f = open(path) # $ SPURIOUS: Alert
9595

9696

9797
@app.route("/not-path/<foo>")
98-
def flask_not_path(foo):
98+
def flask_not_path(foo): # $ Source
9999
# On UNIX systems, this is OK, since without being marked as `<path:foo>`, flask
100100
# routing ensures that `foo` cannot contain forward slashes (not by using %2F either).
101101
path = os.path.join(STATIC_DIR, foo)
102-
f = open(path) # $result=BAD // OK if only running on UNIX systems, NOT OK if could be running on windows
102+
f = open(path) # $ Alert // OK if only running on UNIX systems, NOT OK if could be running on windows
103103

104104

105105
@app.route("/no-dot-dot")
@@ -110,7 +110,7 @@ def no_dot_dot():
110110
# handle if `filename` is an absolute path
111111
if '../' in path:
112112
return "not this time"
113-
f = open(path) # $result=BAD
113+
f = open(path) # $ Alert
114114

115115

116116
@app.route("/no-dot-dot-with-prefix")
@@ -121,15 +121,15 @@ def no_dot_dot_with_prefix():
121121
# Therefore, for UNIX-only programs, the `../` check is enough to stop path injections.
122122
if '../' in path:
123123
return "not this time"
124-
f = open(path) # $result=BAD // OK if only running on UNIX systems, NOT OK if could be running on windows
124+
f = open(path) # $ Alert // OK if only running on UNIX systems, NOT OK if could be running on windows
125125

126126

127127
@app.route("/replace-slash")
128128
def replace_slash():
129129
filename = request.args.get('filename', '')
130130
path = os.path.join(STATIC_DIR, filename)
131131
sanitized = path.replace("/", "_")
132-
f = open(sanitized) # $result=BAD // OK if only running on UNIX systems, NOT OK if could be running on windows
132+
f = open(sanitized) # $ Alert // OK if only running on UNIX systems, NOT OK if could be running on windows
133133

134134

135135
@app.route("/stackoverflow-solution")
@@ -139,7 +139,7 @@ def stackoverflow_solution():
139139
path = os.path.join(STATIC_DIR, filename)
140140
if os.path.commonprefix((os.path.realpath(path), STATIC_DIR)) != STATIC_DIR:
141141
return "not this time"
142-
f = open(path) # $SPURIOUS: result=BAD
142+
f = open(path) # $ SPURIOUS: Alert
143143

144144

145145
SAFE_FILES = ['foo', 'bar', 'baz']
@@ -149,4 +149,4 @@ def safe_set_of_files():
149149
filename = request.args.get('filename', '')
150150
if filename in SAFE_FILES:
151151
path = os.path.join(STATIC_DIR, filename)
152-
f = open(path) # $SPURIOUS: result=BAD
152+
f = open(path) # $ SPURIOUS: Alert
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pathlib
22

3-
from flask import Flask, request
3+
from flask import Flask, request # $ Source
44
app = Flask(__name__)
55

66

@@ -11,7 +11,7 @@
1111
def path_injection():
1212
filename = request.args.get('filename', '')
1313
p = STATIC_DIR / filename
14-
p.open() # $ result=BAD
14+
p.open() # $ Alert
1515

1616
p2 = pathlib.Path(STATIC_DIR, filename)
17-
p2.open() # $ result=BAD
17+
p2.open() # $ Alert

python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os.path
22

3-
from flask import Flask, request
3+
from flask import Flask, request # $ Source
44

55
app = Flask(__name__)
66

@@ -16,21 +16,21 @@ def normalize(x):
1616
@app.route("/path")
1717
def simple():
1818
x = source()
19-
open(x) # $result=BAD
19+
open(x) # $ Alert
2020

2121

2222
@app.route("/path")
2323
def normalization():
2424
x = source()
2525
y = normalize(x)
26-
open(y) # $result=BAD
26+
open(y) # $ Alert
2727

2828

2929
@app.route("/path")
3030
def check():
3131
x = source()
3232
if x.startswith("subfolder/"):
33-
open(x) # $result=BAD
33+
open(x) # $ Alert
3434

3535

3636
@app.route("/path")
@@ -46,4 +46,4 @@ def check_then_normalize():
4646
x = source()
4747
if x.startswith("subfolder/"):
4848
y = normalize(x)
49-
open(y) # $result=BAD
49+
open(y) # $ Alert

0 commit comments

Comments
 (0)