-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Python: Split Insecure Cookie query into multiple queries #20494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
joefarebrother
merged 13 commits into
github:main
from
joefarebrother:python-insecure-cookie-split
Oct 24, 2025
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
7eabed6
Split insecure cookies queries into 3 queries
joefarebrother 04316d3
Update qhelp
joefarebrother 2e95c2b
Split test cases for insecure cookie queries
joefarebrother a9a258e
Add changenote
joefarebrother 6eac6b7
Rename qhelp file
joefarebrother d28e800
Add sensitive data heuristic
joefarebrother 2cffb21
Update and fix tests
joefarebrother 1208195
Align alert messages across languages.
joefarebrother 55fd7c8
Update documentation
joefarebrother 85f8869
Update changenote
joefarebrother 654ed9c
Update integration tests
joefarebrother 9f5bfeb
Update test output
joefarebrother cb7b1ef
Update alert message
joefarebrother File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
|
|
||
| <overview> | ||
| <p>Cookies without the <code>HttpOnly</code> flag set are accessible to JavaScript running in the same origin. | ||
| In case of a Cross-Site Scripting (XSS) vulnerability, the cookie can be stolen by a malicious script. | ||
| If a sensitive cookie does not need to be accessed directly by client-side JS, the <code>HttpOnly</code> flag should be set.</p> | ||
| </overview> | ||
|
|
||
| <recommendation> | ||
| <p>Set <code>httponly</code> to <code>True</code>, or add <code>; HttpOnly;</code> to the cookie's raw header value, to ensure that the cookie is not accessible via JavaScript.</p> | ||
| </recommendation> | ||
|
|
||
| <example> | ||
| <p>In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the case marked BAD they are not set.</p> | ||
| <sample src="examples/InsecureCookie.py" /> | ||
| </example> | ||
|
|
||
| <references> | ||
| <li>PortSwigger: <a href="https://portswigger.net/kb/issues/00500600_cookie-without-httponly-flag-set">Cookie without HttpOnly flag set</a></li> | ||
| <li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a>.</li> | ||
| </references> | ||
|
|
||
| </qhelp> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /** | ||
| * @name Sensitive cookie missing `HttpOnly` attribute. | ||
| * @description Cookies without the `HttpOnly` attribute set can be accessed by JS scripts, making them more vulnerable to XSS attacks. | ||
| * @kind problem | ||
| * @problem.severity warning | ||
| * @security-severity 5.0 | ||
| * @precision high | ||
| * @id py/client-exposed-cookie | ||
| * @tags security | ||
| * external/cwe/cwe-1004 | ||
| */ | ||
|
|
||
| import python | ||
| import semmle.python.dataflow.new.DataFlow | ||
| import semmle.python.Concepts | ||
|
|
||
| from Http::Server::CookieWrite cookie | ||
| where | ||
| cookie.hasHttpOnlyFlag(false) and | ||
| cookie.isSensitive() | ||
| select cookie, "Sensitive server cookie is set without HttpOnly flag." | ||
21 changes: 21 additions & 0 deletions
21
python/ql/src/Security/CWE-1004/examples/InsecureCookie.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| from flask import Flask, request, make_response, Response | ||
|
|
||
|
|
||
| @app.route("/good1") | ||
| def good1(): | ||
| resp = make_response() | ||
| resp.set_cookie("sessionid", value="value", secure=True, httponly=True, samesite='Strict') # GOOD: Attributes are securely set | ||
| return resp | ||
|
|
||
|
|
||
| @app.route("/good2") | ||
| def good2(): | ||
| resp = make_response() | ||
| resp.headers['Set-Cookie'] = "sessionid=value; Secure; HttpOnly; SameSite=Strict" # GOOD: Attributes are securely set | ||
| return resp | ||
|
|
||
| @app.route("/bad1") | ||
| def bad1(): | ||
| resp = make_response() | ||
| resp.set_cookie("sessionid", value="value", samesite='None') # BAD: the SameSite attribute is set to 'None' and the 'Secure' and 'HttpOnly' attributes are set to False by default. | ||
| return resp |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
|
|
||
| <overview> | ||
| <p>Cookies with the <code>SameSite</code> attribute set to <code>'None'</code> will be sent with cross-origin requests. | ||
| This can sometimes allow for Cross-Site Request Forgery (CSRF) attacks, in which a third-party site could perform actions on behalf of a user, if the cookie is used for authentication.</p> | ||
| </overview> | ||
|
|
||
| <recommendation> | ||
| <p>Set the <code>samesite</code> to <code>Lax</code> or <code>Strict</code>, or add <code>; SameSite=Lax;</code>, or | ||
| <code>; SameSite=Strict;</code> to the cookie's raw header value. The default value in most cases is <code>Lax</code>.</p> | ||
| </recommendation> | ||
|
|
||
| <example> | ||
| <p>In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the case marked BAD they are not set.</p> | ||
| <sample src="examples/InsecureCookie.py" /> | ||
| </example> | ||
|
|
||
| <references> | ||
| <li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a>.</li> | ||
| <li>OWASP: <a href="https://owasp.org/www-community/SameSite">SameSite</a>.</li> | ||
| </references> | ||
|
|
||
| </qhelp> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /** | ||
| * @name Sensitive cookie with `SameSite` attribute set to `None`. | ||
| * @description Cookies with `SameSite` set to `None` can allow for Cross-Site Request Forgery (CSRF) attacks. | ||
| * @kind problem | ||
| * @problem.severity warning | ||
| * @security-severity 4.0 | ||
| * @precision high | ||
| * @id py/samesite-none-cookie | ||
| * @tags security | ||
| * external/cwe/cwe-1275 | ||
| */ | ||
|
|
||
| import python | ||
| import semmle.python.dataflow.new.DataFlow | ||
| import semmle.python.Concepts | ||
|
|
||
| from Http::Server::CookieWrite cookie | ||
| where | ||
| cookie.hasSameSiteAttribute(any(Http::Server::CookieWrite::SameSiteNone v)) and | ||
| cookie.isSensitive() | ||
| select cookie, "Sensitive cookie with SameSite set to 'None'." |
21 changes: 21 additions & 0 deletions
21
python/ql/src/Security/CWE-1275/examples/InsecureCookie.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| from flask import Flask, request, make_response, Response | ||
|
|
||
|
|
||
| @app.route("/good1") | ||
| def good1(): | ||
| resp = make_response() | ||
| resp.set_cookie("sessionid", value="value", secure=True, httponly=True, samesite='Strict') # GOOD: Attributes are securely set | ||
| return resp | ||
|
|
||
|
|
||
| @app.route("/good2") | ||
| def good2(): | ||
| resp = make_response() | ||
| resp.headers['Set-Cookie'] = "sessionid=value; Secure; HttpOnly; SameSite=Strict" # GOOD: Attributes are securely set | ||
| return resp | ||
|
|
||
| @app.route("/bad1") | ||
| def bad1(): | ||
| resp = make_response() | ||
| resp.set_cookie("sessionid", value="value", samesite='None') # BAD: the SameSite attribute is set to 'None' and the 'Secure' and 'HttpOnly' attributes are set to False by default. | ||
| return resp |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| category: minorAnalysis | ||
| --- | ||
| * The `py/insecure-cookie` query has been split into multiple queries; with `py/insecure-cookie` checking for cases in which `Secure` flag is not set, `py/client-exposed-cookie` checking for cases in which the `HttpOnly` flag is not set, and the `py/samesite-none` query checking for cases in which the `SameSite` attribute is set to `None`. These queries also now only alert for cases in which the cookie is detected to contain sensitive data. |
3 changes: 3 additions & 0 deletions
3
python/ql/test/query-tests/Security/CWE-1004-NonHttpOnlyCookie/NonHttpOnlyCookie.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| | test.py:8:5:8:38 | ControlFlowNode for Attribute() | Sensitive server cookie is set without HttpOnly flag. | | ||
| | test.py:9:5:9:51 | ControlFlowNode for Attribute() | Sensitive server cookie is set without HttpOnly flag. | | ||
| | test.py:11:5:11:57 | ControlFlowNode for Attribute() | Sensitive server cookie is set without HttpOnly flag. | |
2 changes: 2 additions & 0 deletions
2
python/ql/test/query-tests/Security/CWE-1004-NonHttpOnlyCookie/NonHttpOnlyCookie.qlref
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| query: Security/CWE-1004/NonHttpOnlyCookie.ql | ||
| postprocess: utils/test/InlineExpectationsTestQuery.ql |
12 changes: 12 additions & 0 deletions
12
python/ql/test/query-tests/Security/CWE-1004-NonHttpOnlyCookie/test.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| from flask import Flask, request, make_response | ||
|
|
||
| app = Flask(__name__) | ||
|
|
||
| @app.route("/test") | ||
| def test(): | ||
| resp = make_response() | ||
| resp.set_cookie("oauth", "value1") # $Alert[py/client-exposed-cookie] | ||
| resp.set_cookie("oauth", "value2", secure=True) # $Alert[py/client-exposed-cookie] | ||
| resp.set_cookie("oauth", "value2", httponly=True) | ||
| resp.set_cookie("oauth", "value2", samesite="Strict") # $Alert[py/client-exposed-cookie] | ||
| resp.set_cookie("oauth", "value2", httponly=True, samesite="None") |
2 changes: 2 additions & 0 deletions
2
python/ql/test/query-tests/Security/CWE-1275-SameSiteNoneCookie/SameSiteNoneCookie.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| | test.py:10:5:10:60 | ControlFlowNode for Attribute() | Sensitive cookie with SameSite set to 'None'. | | ||
| | test.py:13:5:13:78 | ControlFlowNode for Attribute() | Sensitive cookie with SameSite set to 'None'. | |
2 changes: 2 additions & 0 deletions
2
python/ql/test/query-tests/Security/CWE-1275-SameSiteNoneCookie/SameSiteNoneCookie.qlref
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| query: Security/CWE-1275/SameSiteNoneCookie.ql | ||
| postprocess: utils/test/InlineExpectationsTestQuery.ql |
15 changes: 15 additions & 0 deletions
15
python/ql/test/query-tests/Security/CWE-1275-SameSiteNoneCookie/test.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from flask import Flask, request, make_response | ||
|
|
||
| app = Flask(__name__) | ||
|
|
||
| @app.route("/test") | ||
| def test(oauth_cookie_name): | ||
| resp = make_response() | ||
| resp.set_cookie("password", "value1") | ||
| resp.set_cookie("authKey", "value2", samesite="Lax") | ||
| resp.set_cookie("session_id", "value2", samesite="None") # $Alert[py/samesite-none-cookie] | ||
| resp.set_cookie("oauth", "value2", secure=True, samesite="Strict") | ||
| resp.set_cookie("oauth", "value2", httponly=True, samesite="Strict") | ||
| resp.set_cookie(oauth_cookie_name, "value2", secure=True, samesite="None") # $Alert[py/samesite-none-cookie] | ||
| resp.set_cookie("not_sensitive", "value2", samesite="None") | ||
|
|
13 changes: 3 additions & 10 deletions
13
python/ql/test/query-tests/Security/CWE-614-InsecureCookie/InsecureCookie.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,3 @@ | ||
| | test.py:10:5:10:37 | ControlFlowNode for Attribute() | Cookie is added without the Secure and HttpOnly attributes properly set. | | ||
| | test.py:11:5:11:50 | ControlFlowNode for Attribute() | Cookie is added without the HttpOnly attribute properly set. | | ||
| | test.py:12:5:12:52 | ControlFlowNode for Attribute() | Cookie is added without the Secure attribute properly set. | | ||
| | test.py:13:5:13:56 | ControlFlowNode for Attribute() | Cookie is added without the Secure and HttpOnly attributes properly set. | | ||
| | test.py:14:5:14:53 | ControlFlowNode for Attribute() | Cookie is added without the Secure and HttpOnly attributes properly set. | | ||
| | test.py:15:5:15:54 | ControlFlowNode for Attribute() | Cookie is added without the Secure, HttpOnly, and SameSite attributes properly set. | | ||
| | test.py:16:5:16:69 | ControlFlowNode for Attribute() | Cookie is added without the HttpOnly attribute properly set. | | ||
| | test.py:17:5:17:71 | ControlFlowNode for Attribute() | Cookie is added without the Secure attribute properly set. | | ||
| | test.py:18:5:18:67 | ControlFlowNode for Attribute() | Cookie is added without the HttpOnly and SameSite attributes properly set. | | ||
| | test.py:19:5:19:69 | ControlFlowNode for Attribute() | Cookie is added without the Secure and SameSite attributes properly set. | | ||
| | test.py:8:5:8:40 | ControlFlowNode for Attribute() | Cookie is added to response without the 'secure' flag being set. | | ||
| | test.py:10:5:10:57 | ControlFlowNode for Attribute() | Cookie is added to response without the 'secure' flag being set. | | ||
| | test.py:11:5:11:60 | ControlFlowNode for Attribute() | Cookie is added to response without the 'secure' flag being set. | |
3 changes: 2 additions & 1 deletion
3
python/ql/test/query-tests/Security/CWE-614-InsecureCookie/InsecureCookie.qlref
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| Security/CWE-614/InsecureCookie.ql | ||
| query: Security/CWE-614/InsecureCookie.ql | ||
| postprocess: utils/test/InlineExpectationsTestQuery.ql |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check warning
Code scanning / CodeQL
Consistent alert message Warning