Skip to content

Commit 00526ee

Browse files
authored
Add security rules for socket binding and Flask debug mode detection
1 parent 2b74515 commit 00526ee

6 files changed

+288
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
id: avoid-bind-to-all-interfaces-python
2+
severity: warning
3+
language: python
4+
message: >-
5+
Running `socket.bind` to 0.0.0.0, or empty string could unexpectedly
6+
expose the server publicly as it binds to all available interfaces.
7+
Consider instead getting correct address from an environment variable or
8+
configuration file.
9+
note: >-
10+
[CWE-200] Exposure of Sensitive Information to an Unauthorized Actor.
11+
[REFERENCES]
12+
- https://owasp.org/Top10/A01_2021-Broken_Access_Control
13+
utils:
14+
MATCH_PATTERN_$S.bind:
15+
kind: expression_statement
16+
all:
17+
- has:
18+
stopBy: neighbor
19+
kind: call
20+
all:
21+
- has:
22+
stopBy: neighbor
23+
kind: attribute
24+
all:
25+
- has:
26+
stopBy: neighbor
27+
kind: identifier
28+
- has:
29+
stopBy: neighbor
30+
kind: identifier
31+
regex: "^bind$"
32+
- has:
33+
stopBy: neighbor
34+
kind: argument_list
35+
has:
36+
stopBy: neighbor
37+
kind: tuple
38+
has:
39+
stopBy: neighbor
40+
kind: string
41+
regex: ^'0.0.0.0'|'::'|''$
42+
- follows:
43+
stopBy: end
44+
kind: expression_statement
45+
has:
46+
stopBy: end
47+
kind: call
48+
has:
49+
stopBy: neighbor
50+
kind: attribute
51+
all:
52+
- has:
53+
stopBy: neighbor
54+
kind: identifier
55+
regex: "^socket$"
56+
- has:
57+
stopBy: neighbor
58+
kind: identifier
59+
regex: "^socket$"
60+
61+
rule:
62+
kind: expression_statement
63+
any:
64+
- matches: MATCH_PATTERN_$S.bind
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
id: debug-enabled-python
2+
severity: warning
3+
language: python
4+
message: >-
5+
Detected Flask app with debug=True. Do not deploy to production with
6+
this flag enabled as it will leak sensitive information. Instead, consider
7+
using Flask configuration variables or setting 'debug' using system
8+
environment variables.
9+
note: >-
10+
[CWE-489] Active Debug Code.
11+
[REFERENCES]
12+
- https://labs.detectify.com/2015/10/02/how-patreon-got-hacked-publicly-exposed-werkzeug-debugger/
13+
utils:
14+
MATCH_PATTERN_debug=True:
15+
kind: call
16+
all:
17+
- has:
18+
stopBy: neighbor
19+
kind: attribute
20+
all:
21+
- has:
22+
stopBy: neighbor
23+
kind: identifier
24+
regex: "^app$"
25+
- has:
26+
stopBy: neighbor
27+
kind: identifier
28+
regex: "^run$"
29+
- has:
30+
stopBy: neighbor
31+
kind: argument_list
32+
has:
33+
stopBy: neighbor
34+
kind: keyword_argument
35+
regex: "^debug=True$"
36+
- any:
37+
- inside:
38+
stopBy: end
39+
kind: if_statement
40+
follows:
41+
stopBy: end
42+
kind: import_from_statement
43+
has:
44+
stopBy: end
45+
kind: dotted_name
46+
has:
47+
stopBy: neighbor
48+
kind: identifier
49+
regex: "^Flask$"
50+
- inside:
51+
stopBy: end
52+
kind: function_definition
53+
follows:
54+
stopBy: end
55+
kind: import_from_statement
56+
has:
57+
stopBy: end
58+
kind: dotted_name
59+
has:
60+
stopBy: neighbor
61+
kind: identifier
62+
regex: "^Flask$"
63+
- inside:
64+
stopBy: end
65+
kind: expression_statement
66+
follows:
67+
stopBy: end
68+
kind: import_from_statement
69+
has:
70+
stopBy: end
71+
kind: dotted_name
72+
has:
73+
stopBy: neighbor
74+
kind: identifier
75+
regex: "^Flask$"
76+
- inside:
77+
stopBy: end
78+
kind: decorated_definition
79+
follows:
80+
stopBy: end
81+
kind: import_from_statement
82+
has:
83+
stopBy: end
84+
kind: dotted_name
85+
has:
86+
stopBy: neighbor
87+
kind: identifier
88+
regex: "^Flask$"
89+
rule:
90+
kind: call
91+
any:
92+
- matches: MATCH_PATTERN_debug=True
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
id: avoid-bind-to-all-interfaces-python
2+
snapshots:
3+
? |
4+
s = socket.socket(doesnt, matter)
5+
s.bind(('',))
6+
s = socket.socket(doesnt, matter)
7+
s.bind(('::', 1337))
8+
s = socket.socket(doesnt, matter)
9+
s.bind(('0.0.0.0', 1337))
10+
: labels:
11+
- source: s.bind(('',))
12+
style: primary
13+
start: 34
14+
end: 47
15+
- source: s
16+
style: secondary
17+
start: 34
18+
end: 35
19+
- source: bind
20+
style: secondary
21+
start: 36
22+
end: 40
23+
- source: s.bind
24+
style: secondary
25+
start: 34
26+
end: 40
27+
- source: ''''''
28+
style: secondary
29+
start: 42
30+
end: 44
31+
- source: ('',)
32+
style: secondary
33+
start: 41
34+
end: 46
35+
- source: (('',))
36+
style: secondary
37+
start: 40
38+
end: 47
39+
- source: s.bind(('',))
40+
style: secondary
41+
start: 34
42+
end: 47
43+
- source: socket
44+
style: secondary
45+
start: 4
46+
end: 10
47+
- source: socket
48+
style: secondary
49+
start: 4
50+
end: 10
51+
- source: socket.socket
52+
style: secondary
53+
start: 4
54+
end: 17
55+
- source: socket.socket(doesnt, matter)
56+
style: secondary
57+
start: 4
58+
end: 33
59+
- source: s = socket.socket(doesnt, matter)
60+
style: secondary
61+
start: 0
62+
end: 33
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
id: debug-enabled-python
2+
snapshots:
3+
? |
4+
from flask import Flask
5+
if __name__ == "__main__":
6+
app.run("0.0.0.0", debug=True)
7+
: labels:
8+
- source: app.run("0.0.0.0", debug=True)
9+
style: primary
10+
start: 51
11+
end: 81
12+
- source: app
13+
style: secondary
14+
start: 51
15+
end: 54
16+
- source: run
17+
style: secondary
18+
start: 55
19+
end: 58
20+
- source: app.run
21+
style: secondary
22+
start: 51
23+
end: 58
24+
- source: debug=True
25+
style: secondary
26+
start: 70
27+
end: 80
28+
- source: ("0.0.0.0", debug=True)
29+
style: secondary
30+
start: 58
31+
end: 81
32+
- source: Flask
33+
style: secondary
34+
start: 18
35+
end: 23
36+
- source: Flask
37+
style: secondary
38+
start: 18
39+
end: 23
40+
- source: from flask import Flask
41+
style: secondary
42+
start: 0
43+
end: 23
44+
- source: app.run("0.0.0.0", debug=True)
45+
style: secondary
46+
start: 51
47+
end: 81
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
id: avoid-bind-to-all-interfaces-python
2+
valid:
3+
- |
4+
s = socket.socket(doesnt, matter)
5+
s.bind(('fe80::34cb:9850:4868:9d2c', 1337))
6+
invalid:
7+
- |
8+
s = socket.socket(doesnt, matter)
9+
s.bind(('',))
10+
s = socket.socket(doesnt, matter)
11+
s.bind(('::', 1337))
12+
s = socket.socket(doesnt, matter)
13+
s.bind(('0.0.0.0', 1337))
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
id: debug-enabled-python
2+
valid:
3+
- |
4+
def env():
5+
app.run("0.0.0.0", debug=os.environ.get("DEBUG", False))
6+
invalid:
7+
- |
8+
from flask import Flask
9+
if __name__ == "__main__":
10+
app.run("0.0.0.0", debug=True)

0 commit comments

Comments
 (0)