python.flask.security.insecure-deserialization.insecure-deserialization

Verifed by r2c
Community Favorite
profile photo of semgrepsemgrep
Author
99,209
Download Count*

Detected the use of an insecure deserialization library in a Flask route. These libraries are prone to code execution vulnerabilities. Ensure user data does not enter this function. To fix this, try to avoid serializing whole objects. Consider instead using a serializer such as JSON.

Run Locally

Run in CI

Defintion

rules:
  - id: insecure-deserialization
    metadata:
      owasp:
        - A08:2017 - Insecure Deserialization
        - A08:2021 - Software and Data Integrity Failures
      cwe:
        - "CWE-502: Deserialization of Untrusted Data"
      references:
        - https://docs.python.org/3/library/pickle.html
      category: security
      technology:
        - flask
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: MEDIUM
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - "Insecure Deserialization "
    message: Detected the use of an insecure deserialization library in a Flask
      route. These libraries are prone to code execution vulnerabilities. Ensure
      user data does not enter this function. To fix this, try to avoid
      serializing whole objects. Consider instead using a serializer such as
      JSON.
    languages:
      - python
    severity: ERROR
    patterns:
      - pattern-inside: |
          @app.route(...)
          def $X(...):
            ...
      - pattern-not: $MODULE.$FUNC("...")
      - pattern-not: $MODULE.$FUNC(open("...", ...))
      - pattern-either:
          - pattern: pickle.$FUNC(...)
          - pattern: _pickle.$FUNC(...)
          - pattern: cPickle.$FUNC(...)
          - pattern: dill.$FUNC(...)
          - pattern: shelve.$FUNC(...)
          - pattern: yaml.load(...)

Examples

insecure-deserialization.py

# example from https://medium.com/gdg-vit/deserialization-attacks-d312fbe58e7d
# flask_app.py
import os
import pickle
from uuid import uuid1
from flask import Flask, make_response, request
from base64 import b64encode, b64decode
# The User Class which assigns a random ID to each connection
class UserID:
    def __init__(self, uuid=None):
        self.uuid = str(uuid1())
    def __str__(self):
        return self.uuid

# The main Flask Backend
app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
    user_obj = request.cookies.get('uuid')
    if user_obj == None:
        msg = "Seems like you didn't have a cookie. No worries! I'll set one now!"
        response = make_response(msg)
        user_obj = UserID()
        # ruleid:insecure-deserialization
        response.set_cookie('uuid', b64encode(pickle.dumps(user_obj)))
        return response
    else:
        # ruleid:insecure-deserialization
        return "Hey there! {}!".format(pickle.loads(b64decode(user_obj)))

@app.route("/ok")
def ok():
    # ok:insecure-deserialization
    novellist = pickle.load(open('./novel/list.dat', "rb"))

if __name__ == "__main__":
    # Using host='0.0.0.0' to accept connections from all IPs
    app.run(host='0.0.0.0')