generated from ossf/project-template
-
Notifications
You must be signed in to change notification settings - Fork 181
CWE-230 Improper handling of missing values #947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
e241ef4
CWE-1095: show that list modification is dangerous (#940)
hedrok 7562241
Guide: Security-Focused Guide for AI Code Assistant Instructions (#936)
balteravishay 3a4f627
CWE-230 Improper handling of missing values
dwiley258 3189a0e
Added updates from comments
dwiley258 2825490
fixed some linting issues to let PR review go ahead
myteron f744186
some cosmetics
myteron bc41add
Update docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-230/README.md
dwiley258 4fd0b26
Update docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-230/README.md
dwiley258 39c2ea0
Delete docs/Secure-Coding-Guide-for-Python/CWE-710/CWE-1095/README.md
dwiley258 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
155 changes: 155 additions & 0 deletions
155
docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-230/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
# CWE-230: Improper Handling of Missing Values | ||
|
||
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]](https://docs.python.org/3/library/statistics.html). | ||
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]](https://en.wikipedia.org/wiki/IEEE_754) a hardware induced compromise. | ||
The [example01.py](example01.py) code demonstrates various comparisons of `float('NaN')` all resulting in `False`. | ||
|
||
```python | ||
# 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 | ||
) | ||
|
||
``` | ||
|
||
## Non-Compliant Code Example | ||
|
||
This noncompliant code example [[2024 docs.python.org]](https://docs.python.org/3/reference/expressions.html#value-comparisons) attempts a direct comparison with `NaN` in `_value == float("NaN")`. | ||
dwiley258 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
*[noncompliant01.py](noncompliant01.py):* | ||
|
||
```python | ||
# SPDX-FileCopyrightText: OpenSSF project contributors | ||
# SPDX-License-Identifier: MIT | ||
""" Non-compliant Code Example """ | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
|
||
|
||
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")) | ||
|
||
``` | ||
|
||
The `balance_is_positive` method returns `True` for all 3 cases instead of throwing an `ValureError` exception for `balance_is_positive("NaN")`. | ||
|
||
## Compliant Solution | ||
|
||
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`. | ||
|
||
|
||
*[compliant01.py](compliant01.py):* | ||
|
||
```python | ||
# 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. | ||
|
||
|
||
*[compliant02.py](compliant02.py):* | ||
|
||
```python | ||
# 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. | ||
|
||
## Automated Detection | ||
|
||
|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| | ||
|
||
## Related Guidelines | ||
|
||
||| | ||
|:---|:---| | ||
|[SEI CERT Coding Standard for Java](https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java)|[NUM07-J. Do not attempt comparisons with NaN](https://wiki.sei.cmu.edu/confluence/display/java/NUM07-J.+Do+not+attempt+comparisons+with+NaN)| | ||
|[ISO/IEC TR 24772:2013](https://wiki.sei.cmu.edu/confluence/display/java/Rule+AA.+References#RuleAA.References-ISO/IECTR24772-2013)|Injection RST| | ||
|[MITRE CWE Pillar](http://cwe.mitre.org/)|[CWE-703: Improper Check or Handling of Exceptional Conditions (mitre.org)](https://cwe.mitre.org/data/definitions/703.html)| | ||
|[MITRE CWE Pillar](http://cwe.mitre.org/)|[CWE-230: Improper Handling of Missing Values](https://cwe.mitre.org/data/definitions/230.html)| | ||
|
||
## Bibliography | ||
|
||
||| | ||
|:---|:---| | ||
|[[Python 3.10.4 docs]](https://docs.python.org/3/library/string.html#formatstrings)|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/)|<https://docs.python.org/3/library/math.html#math.nan> \[Accessed 22 July 2025]| | ||
|[Python docs](https://docs.python.org/3/)|Python Value comparisons<https://docs.python.org/3/reference/expressions.html#value-comparisons> \[Accessed 22 July 2025]| | ||
|[[Wikipedia 2024]](https://realpython.com/python-string-formatting/)|IEEE 754: <https://en.wikipedia.org/wiki/IEEE_754> \[Accessed 22 July 2025]| |
2 changes: 1 addition & 1 deletion
2
docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-230/compliant01.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-230/compliant02.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# 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")) |
172 changes: 0 additions & 172 deletions
172
docs/Secure-Coding-Guide-for-Python/CWE-710/CWE-1095/README.md
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
docs/Secure-Coding-Guide-for-Python/CWE-710/CWE-1095/noncompliant01.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,11 @@ | ||
# SPDX-FileCopyrightText: OpenSSF project contributors | ||
# SPDX-License-Identifier: MIT | ||
""" Non-compliant Code Example """ | ||
userlist = ['Alice', 'Bob', 'Charlie'] | ||
userlist = ['Alice', 'Bob', 'Bill', 'Charlie'] | ||
print(f'Unmodified list: {userlist}') | ||
|
||
for user in userlist: | ||
if user == 'Bob': | ||
if user.startswith('B'): | ||
userlist.remove(user) | ||
|
||
print(f'Modified list: {userlist}') |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.