python.flask.security.injection.user-eval.eval-injection

Verifed by r2c
Community Favorite
profile photo of semgrepsemgrep
Author
180,631
Download Count*

Detected user data flowing into eval. This is code injection and should be avoided.

Run Locally

Run in CI

Defintion

rules:
  - id: eval-injection
    languages:
      - python
    severity: ERROR
    message: Detected user data flowing into eval. This is code injection and should
      be avoided.
    metadata:
      cwe:
        - "CWE-95: Improper Neutralization of Directives in Dynamically
          Evaluated Code ('Eval Injection')"
      owasp:
        - A03:2021 - Injection
      references:
        - https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
      category: security
      technology:
        - flask
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: MEDIUM
      confidence: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    pattern-either:
      - patterns:
          - pattern: eval(...)
          - pattern-either:
              - pattern-inside: |
                  @$APP.route($ROUTE, ...)
                  def $FUNC(..., $ROUTEVAR, ...):
                    ...
                    eval(..., <... $ROUTEVAR ...>, ...)
              - pattern-inside: |
                  @$APP.route($ROUTE, ...)
                  def $FUNC(..., $ROUTEVAR, ...):
                    ...
                    $INTERM = <... $ROUTEVAR ...>
                    ...
                    eval(..., <... $INTERM ...>, ...)
      - pattern: eval(..., <... flask.request.$W.get(...) ...>, ...)
      - pattern: eval(..., <... flask.request.$W[...] ...>, ...)
      - pattern: eval(..., <... flask.request.$W(...) ...>, ...)
      - pattern: eval(..., <... flask.request.$W ...>, ...)
      - patterns:
          - pattern-inside: |
              $INTERM = <... flask.request.$W.get(...) ...>
              ...
              eval(..., <... $INTERM ...>, ...)
          - pattern: eval(...)
      - patterns:
          - pattern-inside: |
              $INTERM = <... flask.request.$W[...] ...>
              ...
              eval(..., <... $INTERM ...>, ...)
          - pattern: eval(...)
      - patterns:
          - pattern-inside: |
              $INTERM = <... flask.request.$W(...) ...>
              ...
              eval(..., <... $INTERM ...>, ...)
          - pattern: eval(...)
      - patterns:
          - pattern-inside: |
              $INTERM = <... flask.request.$W ...>
              ...
              eval(..., <... $INTERM ...>, ...)
          - pattern: eval(...)

Examples

user-eval.py

import flask

app = flask.Flask(__name__)

@app.route("/route_param/<route_param>")
def route_param(route_param):
    print("blah")
    # ruleid: eval-injection
    return eval(route_param)

@app.route("/route_param/<route_param>")
def route_param(route_param):
    print("blah")
    # ok: eval-injection
    return eval("this is safe")

@app.route("/get_param", methods=["GET"])
def get_param():
    param = flask.request.args.get("param")
    # ruleid: eval-injection
    eval(param)

@app.route("/get_param", methods=["GET"])
def get_param():
    param = flask.request.args.get("param")
    # ok: eval-injection
    eval("this is safe")

@app.route("/get_param_inline_concat", methods=["GET"])
def get_param_inline_concat():
    # ruleid: eval-injection
    eval("import " + flask.request.args.get("param"))

@app.route("/get_param_concat", methods=["GET"])
def get_param_concat():
    param = flask.request.args.get("param")
    # ruleid: eval-injection
    eval(param + "+ 'hello'")

@app.route("/get_param_format", methods=["GET"])
def get_param_format():
    param = flask.request.args.get("param")
    # ruleid: eval-injection
    eval("import {}".format(param))

@app.route("/get_param_percent_format", methods=["GET"])
def get_param_percent_format():
    param = flask.request.args.get("param")
    # ruleid: eval-injection
    eval("import %s" % (param,))

@app.route("/post_param", methods=["POST"])
def post_param():
    param = flask.request.form['param']
    if True:
        # ruleid: eval-injection
        eval(param)

@app.route("/format", methods=["POST"])
def format():
    param = "{}".format(flask.request.form['param'])
    print("do things")
    # ruleid: eval-injection
    eval(param)

@app.route("/ok")
def ok():
    eval("This is fine")