python.flask.security.audit.secure-set-cookie.secure-set-cookie

Community Favorite
profile photo of semgrepsemgrep
Author
48,300
Download Count*

Found a Flask cookie with insecurely configured properties. By default the secure, httponly and samesite ar configured insecurely. cookies should be handled securely by setting secure=True, httponly=True, and samesite='Lax' in response.set_cookie(...). If these parameters are not properly set, your cookies are not properly protected and are at risk of being stolen by an attacker. Include the secure=True, httponly=True, samesite='Lax' arguments or set these to be true in the Flask configuration.

Run Locally

Run in CI

Defintion

rules:
  - id: secure-set-cookie
    patterns:
      - pattern-either:
          - pattern-inside: |
              $RESP = flask.make_response(...)
              ...
          - pattern-inside: |
              $RESP = flask.Response(...)
              ...
      - pattern-not: $RESP.set_cookie(..., secure=$A, httponly=$B, samesite=$C, ...)
      - pattern-not: $RESP.set_cookie(..., **$A)
      - pattern: $RESP.set_cookie(...)
    message: Found a Flask cookie with insecurely configured properties.  By default
      the secure, httponly and samesite ar configured insecurely. cookies should
      be handled securely by setting `secure=True`, `httponly=True`, and
      `samesite='Lax'` in response.set_cookie(...). If these parameters are not
      properly set, your cookies are not properly protected and are at risk of
      being stolen by an attacker. Include the `secure=True`, `httponly=True`,
      `samesite='Lax'` arguments or set these to be true in the Flask
      configuration.
    metadata:
      cwe:
        - "CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute"
      owasp:
        - A05:2021 - Security Misconfiguration
      references:
        - https://flask.palletsprojects.com/en/3.0.x/api/#flask.Response.set_cookie
        - https://flask.palletsprojects.com/en/3.0.x/security/#set-cookie-options
      category: security
      technology:
        - python
        - flask
      subcategory:
        - audit
      likelihood: LOW
      impact: LOW
      confidence: LOW
      functional-categories:
        - web::search::cookie-config::flask
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cookie Security
    languages:
      - python
    severity: WARNING

Examples

secure-set-cookie.py

def test1():
    import flask

    response = flask.make_response()

    # ruleid:secure-set-cookie
    response.set_cookie("cookie_name", "cookie_value")

    # ruleid:secure-set-cookie
    response.set_cookie("username","DrewDennison")
    # ruleid:secure-set-cookie
    response.set_cookie("cartTotal",
        generate_cookie_value("DrewDennison"),
        secure=False)

    # ok:secure-set-cookie
    response.set_cookie("user—rights", "admin", secure=True,
      httponly=True, samesite="Lax")

    return response

def test2():
    from flask import make_response
    r = make_response()
    # some values are set but not others

    # ruleid:secure-set-cookie
    r.set_cookie("cookie1", "cookie_value", secure=True)
    # ruleid:secure-set-cookie
    r.set_cookie("cookie2", "cookie_value", httponly=True)
    # ruleid:secure-set-cookie
    r.set_cookie("cookie3", "cookie_value", samesite="Lax")
    # ruleid:secure-set-cookie
    r.set_cookie("cookie4", "cookie_value", secure=True, httponly=True)
    # ruleid:secure-set-cookie
    r.set_cookie("cookie5", "cookie_value", httponly=True, samesite="Lax")

def test3():
    import flask
    response = flask.make_response()
    # all present
    # ok:secure-set-cookie
    response.set_cookie("cookie1", "cookie_value", secure=True, httponly=True, samesite='Lax')
    # ok:secure-set-cookie
    response.set_cookie("cookie2", "cookie_value", secure=True, httponly=True, samesite='Strict')
    # ok:secure-set-cookie
    response.set_cookie("cookie3", "cookie_value", secure=False, httponly=False, samesite=None)

# ok:secure-set-cookie
def set_cookie(settings):
    d = {"hello": "world"}
    d.update(settings)
    return d

def use_cookie(cookie):
    # ok:secure-set-cookie
    foo = set_cookie({"goodbye": "planet"})

# cf. # https://github.com/pallets/flask/blob/b7f6fae9b34341b9be7742b86f6caffe07fc6f25/tests/test_basic.py#L1956
def test_real_code():
    import flask
    app = flask.Flask(__name__)
    @app.route("/")
    def index():
        r = flask.Response("", status=204)
        # ruleid: secure-set-cookie
        r.set_cookie("foo", "bar" * 100)
        return r

# cf. https://github.com/cruzegoodin/TSC-ShippingDetails/blob/cceee79014623c5ac8fb042b8301a427743627d6/venv/lib/python2.7/site-packages/pip/_vendor/requests/cookies.py#L306
import copy
import time
import collections
from .compat import cookielib, urlparse, urlunparse, Morsel
def merge_cookies(cookiejar, cookies):
    if not isinstance(cookiejar, cookielib.CookieJar):
        raise ValueError('You can only merge into CookieJar')
    if isinstance(cookies, dict):
        cookiejar = cookiejar_from_dict(
            cookies, cookiejar=cookiejar, overwrite=False)
    elif isinstance(cookies, cookielib.CookieJar):
        try:
            cookiejar.update(cookies)
        except AttributeError:
            for cookie_in_jar in cookies:
                # ok:secure-set-cookie
                cookiejar.set_cookie(cookie_in_jar)
    return cookiejar