python.flask.security.audit.wtf-csrf-disabled.flask-wtf-csrf-disabled

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

Setting 'WTF_CSRF_ENABLED' to 'False' explicitly disables CSRF protection.

Run Locally

Run in CI

Defintion

rules:
  - id: flask-wtf-csrf-disabled
    message: Setting 'WTF_CSRF_ENABLED' to 'False' explicitly disables CSRF protection.
    options:
      symbolic_propagation: true
    metadata:
      cwe:
        - "CWE-352: Cross-Site Request Forgery (CSRF)"
      owasp:
        - A01:2021 - Broken Access Control
      references:
        - https://flask-wtf.readthedocs.io/en/1.2.x/csrf/
      category: security
      technology:
        - flask
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: MEDIUM
      confidence: LOW
      functional-categories:
        - web::search::csrf-config::flask
        - web::search::csrf-config::flask-wtf
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cross-Site Request Forgery (CSRF)
    severity: WARNING
    languages:
      - python
    patterns:
      - pattern-either:
          - patterns:
              - pattern-either:
                  - pattern: $APP.config["WTF_CSRF_ENABLED"] = $FALSE
                  - pattern: $APP.config.WTF_CSRF_ENABLED = $FALSE
                  - patterns:
                      - pattern: |
                          $APP.config.$UPDATE(
                            ...,
                            WTF_CSRF_ENABLED = $FALSE,
                            ...
                          )
                      - pattern-not-inside: |
                          $APP.config.$UPDATE(
                              ...,
                              TESTING=True,
                              ...
                          )
                      - pattern-not-inside: |
                          $APP.config.$UPDATE(
                              ...,
                              DEBUG=True,
                              ...
                          )
                      - metavariable-regex:
                          metavariable: $UPDATE
                          regex: ^(update|from_mapping)$
                  - pattern: |
                      $OBJ = $CLASS()
                      ...
                      $OBJ.WTF_CSRF_ENABLED = $FALSE
                      ...
                      $APP.config.from_object($OBJ, ...)
                  - pattern: |
                      WTF_CSRF_ENABLED = $FALSE
                      ...
                      $APP.config.from_object(__name__)
              - metavariable-regex:
                  metavariable: $FALSE
                  regex: ^(False)$
              - focus-metavariable: $FALSE
    fix: "True"

Examples

wtf-csrf-disabled.py

import flask
from flask import response as r

app = flask.Flask(__name__)
# ruleid:flask-wtf-csrf-disabled
app.config['WTF_CSRF_ENABLED'] = False

# ruleid:flask-wtf-csrf-disabled
app.config["WTF_CSRF_ENABLED"] = False

# ok: flask-wtf-csrf-disabled
app.config["WTF_CSRF_ENABLED"] = True
# ok: flask-wtf-csrf-disabled
app.config["SESSION_COOKIE_SECURE"] = False

# ruleid: flask-wtf-csrf-disabled
app.config.WTF_CSRF_ENABLED = False
# ok: flask-wtf-csrf-disabled
app.config.WTF_CSRF_ENABLED = True

# DICT UPDATE
################

app.config.update(
    SECRET_KEY='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf',
    # ruleid: flask-wtf-csrf-disabled
    WTF_CSRF_ENABLED = False,
    TESTING=False
)

# It's okay to do this during testing
app.config.update(
    SECRET_KEY='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf',
    # ok: flask-wtf-csrf-disabled
    WTF_CSRF_ENABLED = False,
    TESTING=True
)

# FROM OBJECT
################

# custom class
appconfig = MyAppConfig()
# ruleid: flask-wtf-csrf-disabled
appconfig.WTF_CSRF_ENABLED = False

app.config.from_object(appconfig)

# this file itself
SECRET_KEY = 'development key'
# ruleid: flask-wtf-csrf-disabled
WTF_CSRF_ENABLED = False

app.config.from_object(__name__)

# FROM MAPPING
################

app.config.from_mapping(
    SECRET_KEY='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf',
    # ruleid: flask-wtf-csrf-disabled
    WTF_CSRF_ENABLED = False,
)

# It's okay to do this during testing
app.config.from_mapping(
    SECRET_KEY='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf',
    # ok: flask-wtf-csrf-disabled
    WTF_CSRF_ENABLED = False,
    TESTING=True
)

@app.route("/index")
def index():
    return 'hello world'