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 .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
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.
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.
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.
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
References
External resources and documentation
Similar Rules
Explore related security rules for Python
Flask CSV Injection
User input from Flask request parameters flows to csv.writer.writerow() or writerows() without formula character sanitization. Strip or escape leading =, +, -, @ characters to prevent spreadsheet formula injection.
Django Command Injection via os.system()
User input flows to os.system(), enabling arbitrary OS command execution with the privileges of the Django process.
HTTP Request Without TLS (requests library)
HTTP URLs in requests calls transmit data in plaintext without encryption. Use HTTPS URLs for sensitive data transmission.
Frequently Asked Questions
Common questions about Flask NaN Injection via float()
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.