Skip to content

Conversation

joefarebrother
Copy link
Contributor

Splits the py/insecure-cookie query into py/insecure-cookie, py/client-exposed-cookie, and py/samesite-none-cookie.
This is closer to how these queries are handled in JS with js/clear-text-cookie, js/client-exposed-cookie, and js/samesite-none-cookie queries.

@joefarebrother joefarebrother requested a review from a team as a code owner September 19, 2025 14:32
@Copilot Copilot AI review requested due to automatic review settings September 19, 2025 14:32
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR splits the existing py/insecure-cookie query into three separate, more focused queries to better align with JavaScript's cookie security query structure. The original query checked for multiple cookie security attributes in a single query, while the new approach separates concerns into distinct queries.

  • Refactors py/insecure-cookie to only check for missing Secure attribute
  • Creates new py/client-exposed-cookie query for missing HttpOnly attribute
  • Creates new py/samesite-none-cookie query for SameSite=None attribute issues

Reviewed Changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated no comments.

Show a summary per file
File Description
python/ql/src/Security/CWE-614/InsecureCookie.ql Simplified to only check for missing Secure attribute
python/ql/src/Security/CWE-1004/NonHttpOnlyCookie.ql New query for missing HttpOnly attribute
python/ql/src/Security/CWE-1275/SameSiteNoneCookie.ql New query for SameSite=None issues
python/ql/test/query-tests/Security/CWE-614-InsecureCookie/test.py Updated test with inline expectations for new query behavior
python/ql/src/change-notes/2025-09-19-insecure-cookie.md Documents the query split changes
Comments suppressed due to low confidence (2)

@joefarebrother joefarebrother marked this pull request as draft September 19, 2025 21:41
@joefarebrother joefarebrother changed the title Python: Split Insecure Cookie query into multiple queries [Draft] Python: Split Insecure Cookie query into multiple queries Sep 19, 2025
Copy link
Contributor

QHelp previews:

python/ql/src/Security/CWE-1004/NonHttpOnlyCookie.qhelp

Sensitive cookie missing HttpOnly attribute.

Cookies without the HttpOnly 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 HttpOnly flag should be set.

Recommendation

Set httponly to True, or add ; HttpOnly; to the cookie's raw header value, to ensure that the cookie is not accessible via JavaScript.

Example

In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the case marked BAD they are not set.

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

References

python/ql/src/Security/CWE-1275/SameSiteNoneCookie.qhelp

Sensitive cookie with SameSite attribute set to None.

Cookies with the SameSite attribute set to 'None' 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.

Recommendation

Set the samesite to Lax or Strict, or add ; SameSite=Lax;, or ; SameSite=Strict; to the cookie's raw header value. The default value in most cases is Lax.

Example

In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the case marked BAD they are not set.

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

References

python/ql/src/Security/CWE-614/InsecureCookie.qhelp

Failure to use secure cookies

Cookies without the Secure flag set may be transmitted using HTTP instead of HTTPS. This leaves them vulnerable to being read by a third party attacker. If a sensitive cookie such as a session key is intercepted this way, it would allow the attacker to perform actions on a user's behalf.

Recommendation

Always set secure to True, or add ; Secure; to the cookie's raw header value, to ensure SSL is used to transmit the cookie with encryption.

Example

In the following examples, the cases marked GOOD show secure cookie attributes being set; whereas in the case marked BAD they are not set.

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

References

@joefarebrother joefarebrother marked this pull request as ready for review September 24, 2025 10:12
@joefarebrother joefarebrother changed the title [Draft] Python: Split Insecure Cookie query into multiple queries Python: Split Insecure Cookie query into multiple queries Sep 24, 2025
Comment on lines +17 to +21
from Http::Server::CookieWrite cookie
where
cookie.hasHttpOnlyFlag(false) and
cookie.isSensitive()
select cookie, "Sensitive server cookie is set without HttpOnly flag."

Check warning

Code scanning / CodeQL

Consistent alert message Warning

The py/client-exposed-cookie query does not have the same alert message as js.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant