Flask NaN Injection via float()

LOW

User input from Flask request parameters flows to float() which can produce NaN or Inf values. Validate and reject non-finite float values with math.isnan() and math.isinf().

Rule Information

Language
Python
Category
Flask
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonflasknan-injectiontype-confusionfloat-conversionnumeric-validationcross-fileinter-proceduraltaint-analysisCWE-704OWASP-A03
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset python/PYTHON-FLASK-SEC-010 --project .
1
2
3
4
5
6
7
8
9
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

About This Rule

Understanding the vulnerability and how it is detected

This rule detects NaN (Not a Number) injection in Flask applications where user- controlled input from HTTP request parameters flows to Python's float() built-in without subsequent validation for non-finite values. Python's float() accepts the special string literals "nan", "inf", "-inf", "infinity", and "+infinity" (case-insensitive) and converts them to the IEEE 754 special float values NaN and Infinity.

These special float values propagate through arithmetic in unexpected ways: NaN comparisons always return False (NaN != NaN, NaN < 0 is False, NaN > 0 is False), Inf causes overflow in operations expecting bounded values, and NaN serialized to JSON via Python's json module produces invalid JSON (json.dumps({'x': float('nan')}) outputs {"x": NaN} which is not valid JSON and may cause downstream parsing failures or type confusion in JavaScript consumers).

The rule traces tainted strings from Flask request sources to the float() call at argument position 0. Using int() on the result is recognized as a sanitizer because int(float('nan')) raises ValueError, effectively rejecting NaN. The correct fix is to validate the result of float() with math.isnan() and math.isinf() before using the value in calculations, storage, or serialization.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Invalid JSON Output Causing API Client Failures

Python's json module serializes float('nan') as NaN and float('inf') as Infinity, both of which are not valid JSON (RFC 8259). API clients that use strict JSON parsers throw exceptions on these values. An attacker who can supply "nan" as a numeric parameter can cause downstream service failures by forcing invalid JSON responses from the Flask application.

2

Arithmetic Logic Bypass via NaN Comparisons

NaN comparisons always return False in Python. Code like if price < 0: raise ValueError fails silently when price is NaN because NaN < 0 is False and NaN >= 0 is also False. An attacker who injects NaN into a price or quantity field may bypass validation logic that relies on numeric comparisons, potentially submitting orders with NaN prices to financial systems.

3

Database and ORM Type Errors

Storing NaN or Inf in database columns typed as NUMERIC, DECIMAL, or FLOAT causes constraint violations in strict databases (PostgreSQL rejects NaN in some contexts) or silent corruption in lenient ones. This can cause cascading failures in reporting, aggregation queries, and data exports.

4

Denial of Service via Propagating NaN

NaN and Inf propagate silently through calculations. A NaN that enters a statistical computation (average, standard deviation, percentile) corrupts the entire result without raising an exception, potentially causing the application to return None or crash in downstream code that does not expect these values.

How to Fix

Recommended remediation steps

  • 1After calling float() on user input, always validate the result with math.isfinite() (which rejects both NaN and Inf in a single call) before using the value in calculations or storage.
  • 2Use int() conversion after float() when integer precision is required -- int() raises ValueError for NaN and OverflowError for Inf, both of which reject the problematic values.
  • 3When serializing numeric values to JSON, use a custom JSON encoder that raises an error on non-finite floats rather than producing invalid JSON output.
  • 4Validate numeric bounds (minimum and maximum acceptable values) in addition to finiteness -- this catches values that are technically finite but outside valid business ranges.
  • 5Consider using Pydantic or marshmallow for request data validation -- both libraries reject NaN and Inf by default when validating float fields.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

Scope: global (cross-file taint tracking across the entire project). Sources: Flask HTTP input methods -- request.args.get(), request.form.get(), request.values.get() -- which deliver string representations of user-supplied values that may include "nan", "inf", or "-inf". Sinks: float(). The .tracks(0) parameter targets argument position 0, the string value being converted to a float. This is where the NaN/Inf injection occurs -- float() accepts these special string values without error. Sanitizers: int() is recognized as a sanitizer because int(float('nan')) raises ValueError, effectively validating that the float is a normal finite integer-representable number. Flows through int() are treated as sanitized because the ValueError propagation forces the application to handle the invalid input explicitly. The rule traces tainted strings through variable assignments and function calls to the float() sink, catching patterns where the conversion happens in a utility function separate from the Flask route handler.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

OWASP Top 10
A03:2021 - Injection (type coercion injection via numeric inputs)
CWE Top 25
CWE-704 -- Incorrect Type Conversion/Cast in software weakness catalog
NIST SP 800-53
SI-10: Information Input Validation -- validate numeric inputs for acceptable ranges
PCI DSS v4.0
Requirement 6.2.4 -- validate all input data types including numeric fields
ASVS v4.0
V5.1.3 -- verify that all input validation is performed server-side

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Flask NaN Injection via float()

NaN injection is LOW severity because it requires specific downstream code patterns to be exploitable (comparisons that assume finite values, JSON serialization without validation). It is not directly exploitable for code execution or data theft in most cases. However, it is worth fixing because the bugs it enables -- silent validation bypasses, invalid JSON output, database errors -- are subtle and hard to diagnose.
In Python, any comparison involving NaN returns False: float('nan') > 0 is False, float('nan') < 0 is False, float('nan') == 0 is False, float('nan') != 0 is True. Code like if value < 0: raise ValueError('negative not allowed') silently accepts NaN because NaN < 0 is False. The validator logic assumes finite values.
Yes. math.isfinite(x) returns True only if x is a regular finite number (not NaN, not +Inf, not -Inf). It is equivalent to not math.isnan(x) and not math.isinf(x) in a single call. Use math.isfinite() as the primary validation check.
PostgreSQL's NUMERIC and DECIMAL types do accept NaN (it represents "not a number" in SQL numeric contexts). However, NaN in a NUMERIC column causes unexpected behavior in aggregate functions (SUM, AVG return NaN), ORDER BY comparisons (NaN sorts inconsistently), and application code that reads the value and applies comparisons. FLOAT/DOUBLE columns in PostgreSQL also accept NaN. Prevent storage of NaN with a CHECK constraint or application-level validation.
The rule fires on tainted flows to float() at position 0. If the input is validated against an allowlist or pattern before the taint reaches float(), and the analysis recognizes that validation as sanitizing, no finding is reported. If the validation happens after float() (e.g., check math.isfinite after converting), the finding still fires because the risky conversion happens before validation -- though the code may be correct, adding the check after conversion is the right pattern.
Catching ValueError from float() handles invalid strings (e.g., "abc") but does not help with NaN and Inf because float('nan') and float('inf') do not raise ValueError -- they succeed and return the special float values. You need an explicit check with math.isfinite() after the float() call.
Pydantic v2 with strict mode rejects NaN and Inf for float fields by default. Pydantic v1 allows NaN in float fields unless you add a validator. If you use Pydantic for request parsing, verify your model's behavior by passing "nan" as a float field value in your tests. If the model accepts it, add a @validator that calls math.isfinite().

New feature

Get these findings posted directly on your GitHub pull requests

The Flask NaN Injection via float() rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works