python.django.security.nan-injection.nan-injection

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Found user input going directly into typecast for bool(), float(), or complex(). This allows an attacker to inject Python's not-a-number (NaN) into the typecast. This results in undefind behavior, particularly when doing comparisons. Either cast to a different type, or add a guard checking for all capitalizations of the string 'nan'.

Run Locally

Run in CI

Defintion

rules:
  - id: nan-injection
    message: Found user input going directly into typecast for bool(), float(), or
      complex(). This allows an attacker to inject Python's not-a-number (NaN)
      into the typecast. This results in undefind behavior, particularly when
      doing comparisons. Either cast to a different type, or add a guard
      checking for all capitalizations of the string 'nan'.
    languages:
      - python
    severity: ERROR
    mode: taint
    pattern-sources:
      - patterns:
          - pattern-inside: |
              def $FUNC(request, ...):
                ...
          - pattern-either:
              - pattern: request.$PROPERTY.get(...)
              - pattern: request.$PROPERTY[...]
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern: float(...)
              - pattern: bool(...)
              - pattern: complex(...)
          - pattern-not-inside: |
              if $COND:
                ...
              ...
    pattern-sanitizers:
      - pattern: $ANYTHING(...)
        not_conflicting: true
    metadata:
      references:
        - https://discuss.python.org/t/nan-breaks-min-max-and-sorting-functions-a-solution/2868
        - https://blog.bitdiscovery.com/2021/12/python-nan-injection/
      category: security
      cwe:
        - "CWE-704: Incorrect Type Conversion or Cast"
      technology:
        - django
      subcategory:
        - vuln
      impact: MEDIUM
      likelihood: MEDIUM
      confidence: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Improper Validation

Examples

nan-injection.py

import models
from django.http import HttpResponse
from app import get_price, deny, buy, fetch_obj


class Person(models.Model):
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    birth_date = models.DateField(...)


##### True Positives #########
def test1(request):
    tid = request.POST.get("tid")

    price = get_price()

    # ruleid: nan-injection
    x = float(tid)

    if x < price:
        return deny()
    return buy()

def test2(request):
    tid = request.POST.get("tid")

    # ruleid: nan-injection
    bool(tid)

    # ruleid: nan-injection
    complex(tid)

def test3(request, something_else):
    tid = request.GET['tid']

    # ruleid: nan-injection
    float(tid)

    # ruleid: nan-injection
    bool(tid)

    # ruleid: nan-injection
    complex(tid)

def ok1(request, something_else):
    tid = request.POST.get("tid")

    obj = fetch_obj(tid)

    # ok: nan-injection
    float(obj.num)

def ok2(request, something_else):
    tid = request.POST.get("tid")

    # ok: nan-injection
    int(float(tid))

    # ok: nan-injection
    float(int(tid))

    # ok: nan-injection
    int(bool(tid))

def ok3(request):
    tid = request.POST.get("tid")

    if tid.lower() == "nan":
        raise ValueError

    # ok: nan-injection 
    num = float(tid)
    if num > get_price():
        buy()
    deny()