The NaN
value should be stripped before as they can cause surprising or undefined behaviours in the statistics functions that sort or count occurrences [2024 doc.python.org].
In python, some datasets use NaN
(not-a-number) to represent the missing data. This can be problematic as the NaN
values are unordered. Any ordered comparison of a number to a not-a-number value are False
. A counter-intuitive implication is that not-a-number
values are not equal to themselves.
This behavior is compliant with IEEE 754[2024 Wikipedia] a hardware induced compromise.
The example01.py code demonstrates various comparisons of float('NaN')
all resulting in False
.
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
""" Code Example """
foo = float('NaN')
print(f"foo={foo} type = {type(foo)}")
print(foo == float("NaN") or
foo is float("NaN") or
foo < 3 or
foo == foo or
foo is None
)
This noncompliant code example [2024 docs.python.org] attempts a direct comparison with NaN
in _value == float("NaN")
.
noncompliant01.py:
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
""" Non-compliant Code Example """
def balance_is_positive(value: str) -> bool:
"""Returns True if there is still enough value for a transaction"""
_value = float(value)
if _value == float("NaN") or _value is float("NaN") or _value is None:
raise ValueError("Expected a float")
if _value <= 0:
return False
else:
return True
#####################
# attempting to exploit above code example
#####################
print(balance_is_positive("0.01"))
print(balance_is_positive("0.001"))
print(balance_is_positive("NaN"))
In the compliant01.py
code example, the method Decimal.quantize
is used to gain control over known rounding errors in floating point values.
The decision by the balance_is_positive
method is to ROUND_DOWN
instead of the default ROUND_HALF_EVEN
.
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
""" Compliant Code Example """
from decimal import ROUND_DOWN, Decimal
def balance_is_positive(value: str) -> bool:
"""Returns True if there is still enough value for a transaction"""
# TODO: additional input sanitation for expected type
_value = Decimal(value)
# TODO: exception handling
return _value.quantize(Decimal(".01"), rounding=ROUND_DOWN) > Decimal("0.00")
#####################
# attempting to exploit above code example
#####################
print(balance_is_positive("0.01"))
print(balance_is_positive("0.001"))
print(balance_is_positive("NaN"))
Decimal
throws a decimal.InvalidOperation
for NaN
values, the controlled rounding causes only "0.01"
to return True
.
In compliant02.py
we use the math.isnan
to verify if the value passed is a valid float
value.
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
""" Compliant Code Example """
import math
def balance_is_positive(value: str) -> bool:
"""Returns True if there is still enough value for a transaction"""
_value = float(value)
if math.isnan(_value) or _value is None:
raise ValueError("Expected a float")
if _value < 0.01:
return False
else:
return True
#####################
# attempting to exploit above code example
#####################
print(balance_is_positive("0.01"))
print(balance_is_positive("0.001"))
print(balance_is_positive("NaN"))
The balance_is_poitive
method will raise an ValueError
for NaN
values.
Tool | Version | Checker | Description |
---|---|---|---|
Bandit | 1.7.4 on Python 3.10.4 | Not Available | |
flake8 | flake8-4.0.1 on python 3.10.4 | Not Available |
[Python 3.10.4 docs] | Format String Syntax. Available from: https://docs.python.org/3/library/string.html#formatstrings [Accessed 22 July 2025] |
Python docs | https://docs.python.org/3/library/math.html#math.nan [Accessed 22 July 2025] |
Python docs | Python Value comparisonshttps://docs.python.org/3/reference/expressions.html#value-comparisons [Accessed 22 July 2025] |
[Wikipedia 2024] | IEEE 754: https://en.wikipedia.org/wiki/IEEE_754 [Accessed 22 July 2025] |