Skip to content

Commit 32fbe52

Browse files
Model cookie attributes for Django and Flask
1 parent 6a7bdaf commit 32fbe52

File tree

4 files changed

+84
-10
lines changed

4 files changed

+84
-10
lines changed

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,6 +2186,48 @@ module PrivateDjango {
21862186
override DataFlow::Node getValueArg() {
21872187
result in [this.getArg(1), this.getArgByName("value")]
21882188
}
2189+
2190+
override predicate hasSecureFlag(boolean b) {
2191+
super.hasSecureFlag(b)
2192+
or
2193+
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("secure") |
2194+
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
2195+
b = bool.booleanValue()
2196+
)
2197+
or
2198+
not exists(this.getArgByName("secure")) and
2199+
b = false
2200+
}
2201+
2202+
override predicate hasHttpOnlyFlag(boolean b) {
2203+
super.hasHttpOnlyFlag(b)
2204+
or
2205+
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("httponly") |
2206+
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
2207+
b = bool.booleanValue()
2208+
)
2209+
or
2210+
not exists(this.getArgByName("httponly")) and
2211+
b = false
2212+
}
2213+
2214+
override predicate hasSameSiteFlag(boolean b) {
2215+
super.hasHttpOnlyFlag(b)
2216+
or
2217+
exists(DataFlow::Node arg, StringLiteral str | arg = this.getArgByName("samesite") |
2218+
DataFlow::localFlow(DataFlow::exprNode(str), arg) and
2219+
(
2220+
str.getText().toLowerCase() = ["strict", "lax"] and
2221+
b = true
2222+
or
2223+
str.getText().toLowerCase() = "none" and
2224+
b = false
2225+
)
2226+
)
2227+
or
2228+
not exists(this.getArgByName("samesite")) and
2229+
b = true // Lax is the default
2230+
}
21892231
}
21902232

21912233
/**

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,48 @@ module Flask {
593593
override DataFlow::Node getNameArg() { result in [this.getArg(0), this.getArgByName("key")] }
594594

595595
override DataFlow::Node getValueArg() { result in [this.getArg(1), this.getArgByName("value")] }
596+
597+
override predicate hasSecureFlag(boolean b) {
598+
super.hasSecureFlag(b)
599+
or
600+
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("secure") |
601+
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
602+
b = bool.booleanValue()
603+
)
604+
or
605+
not exists(this.getArgByName("secure")) and
606+
b = false
607+
}
608+
609+
override predicate hasHttpOnlyFlag(boolean b) {
610+
super.hasHttpOnlyFlag(b)
611+
or
612+
exists(DataFlow::Node arg, BooleanLiteral bool | arg = this.getArgByName("httponly") |
613+
DataFlow::localFlow(DataFlow::exprNode(bool), arg) and
614+
b = bool.booleanValue()
615+
)
616+
or
617+
not exists(this.getArgByName("httponly")) and
618+
b = false
619+
}
620+
621+
override predicate hasSameSiteFlag(boolean b) {
622+
super.hasHttpOnlyFlag(b)
623+
or
624+
exists(DataFlow::Node arg, StringLiteral str | arg = this.getArgByName("samesite") |
625+
DataFlow::localFlow(DataFlow::exprNode(str), arg) and
626+
(
627+
str.getText().toLowerCase() = ["strict", "lax"] and
628+
b = true
629+
or
630+
str.getText().toLowerCase() = "none" and
631+
b = false
632+
)
633+
)
634+
or
635+
not exists(this.getArgByName("samesite")) and
636+
b = true // Lax is the default
637+
}
596638
}
597639

598640
/**

python/ql/test/experimental/query-tests/Security/CWE-614/CookieInjection.expected

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,12 @@ subpaths
3434
| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its httponly flag is not properly set. | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input |
3535
| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its samesite flag is not properly set. | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input |
3636
| django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | Cookie is constructed from a $@,and its secure flag is not properly set. | django_bad.py:20:21:20:56 | ControlFlowNode for Attribute() | user-supplied input |
37-
| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its httponly flag is not properly set. | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input |
3837
| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its samesite flag is not properly set. | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input |
39-
| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its secure flag is not properly set. | django_bad.py:27:33:27:67 | ControlFlowNode for Attribute() | user-supplied input |
40-
| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its httponly flag is not properly set. | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input |
4138
| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its samesite flag is not properly set. | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input |
42-
| django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | django_bad.py:27:30:27:124 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its secure flag is not properly set. | django_bad.py:27:71:27:106 | ControlFlowNode for Attribute() | user-supplied input |
4339
| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its httponly flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |
4440
| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its samesite flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |
4541
| flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:24:21:24:40 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its secure flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |
4642
| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its httponly flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |
4743
| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its samesite flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |
4844
| flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:24:49:24:69 | ControlFlowNode for Subscript | Cookie is constructed from a $@,and its secure flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |
49-
| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its httponly flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |
5045
| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its samesite flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |
51-
| flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_bad.py:32:34:32:98 | ControlFlowNode for Fstring | Cookie is constructed from a $@,and its secure flag is not properly set. | flask_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-supplied input |

python/ql/test/experimental/query-tests/Security/CWE-614/InsecureCookie.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. |
88
| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. |
99
| django_bad.py:19:5:21:66 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. |
10-
| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the 'httponly' flag properly set. |
1110
| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the 'samesite' flag properly set. |
12-
| django_bad.py:27:5:27:26 | ControlFlowNode for Subscript | Cookie is added without the 'secure' flag properly set. |
1311
| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. |
1412
| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. |
1513
| django_good.py:19:5:19:44 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. |
@@ -22,9 +20,7 @@
2220
| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. |
2321
| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. |
2422
| flask_bad.py:24:5:25:52 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. |
25-
| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the 'httponly' flag properly set. |
2623
| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the 'samesite' flag properly set. |
27-
| flask_bad.py:32:5:32:30 | ControlFlowNode for Subscript | Cookie is added without the 'secure' flag properly set. |
2824
| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the 'httponly' flag properly set. |
2925
| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the 'samesite' flag properly set. |
3026
| flask_good.py:23:5:23:57 | ControlFlowNode for Attribute() | Cookie is added without the 'secure' flag properly set. |

0 commit comments

Comments
 (0)