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

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

Found a Flask cookie without secure, httponly, or samesite correctly set. Flask 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: $RESPONSE.set_cookie(..., secure=$A, httponly=$B, samesite=$C, ...)
      - pattern-not: $RESPONSE.set_cookie(..., **$A)
      - pattern: $RESPONSE.set_cookie(...)
    message: Found a Flask cookie without secure, httponly, or samesite correctly
      set. Flask 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://blog.r2c.dev/2020/bento-check-keeping-cookies-safe-in-flask/
        - https://bento.dev/checks/flask/secure-set-cookie/
        - https://flask.palletsprojects.com/en/1.1.x/security/#set-cookie-options
      category: security
      technology:
        - flask
      subcategory:
        - audit
      likelihood: LOW
      impact: LOW
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
    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")
    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