Avoiding NULL Pointer Dereference is crucial for preventing runtime errors, and ensuring that your code executes successfully.
If the data originates from a lesser trusted source, verifying that objects are not None becomes a mandatory security measure to prevent potential vulnerabilities such as unauthorized access or unexpected behavior. However, when dealing with data from trusted and well-controlled sources, the primary concern shifts from a security one, to more of a stability issue as per CWE-390.
Noncompliant01.py
defines a function is_valid_name()
that checks if a certain name is properly defined (contains exactly two words, both capitalized):
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
""" Non-compliant Code Example """
def is_valid_name(s: str) -> bool:
""" Check if the input is a name with 2 capitalised Strings """
names = s.split()
if len(names) != 2:
return False
return s.istitle()
#####################
# Attempting to exploit above code example
#####################
name = is_valid_name(None)
print(name)
The is_valid_name()
function could get called with a null argument, which raises an AttributeError
due to the NoneType
object not having any split
attribute.
The compliant01.py
code includes the same implementation as the previous noncompliant01.py
but now checks if the string is None
.
The type hint Optional [str] can be added to the method signature to show that it could be called with None (where Optional[X] is equivalent to X |
None or Union[X, None] ). |
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
""" Compliant Code Example """
from typing import Optional
def is_valid_name(s: Optional[str]) -> bool:
""" Check if the input is a name with 2 capitalised Strings """
if s is None:
return False
names = s.split()
if len(names) != 2:
return False
return s.istitle()
#####################
# Attempting to exploit above code example
#####################
name = is_valid_name(None)
print(name)
Noncompliant02.py
demonstrates the process of checking the number of students in a given classroom. In certain scenarios, such as a small school without a certain grade, the number of students in a classroom may legitimately be represented as None
.
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Non-compliant Code Example"""
def print_number_of_students(classroom: list[str]):
"""Print the number of students in a classroom"""
print(f"The classroom has {len(classroom)} students.")
#####################
# Attempting to exploit above code example
#####################
print_number_of_students(None)
The code example attempts to directly call len()
on a non-array value, in this case on None
, which will raise a TypeError
. Such unchecked dereferencing of a None
value could result in an application crash or denial of service, impacting system availability.
The compliant02.py
solution safely checks whether the classroom object is an array (or list) before calling the len()
thereby preventing a potential TypeError
and avoiding loss of availability.
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Compliant Code Example"""
def print_number_of_students(classroom: list[str]):
"""Print the number of students in a classroom"""
if isinstance(classroom, list):
print(f"The classroom has {len(classroom)} students.")
else:
print("Given object is not a classroom.")
#####################
# Attempting to exploit above code example
#####################
print_number_of_students(None)
Noncompliant03.py
demonstrates an incorrect example of checking for whether the variable passed is a list. If the variable is not a list, then the code example attempts to raise None
.
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Non-compliant Code Example"""
def print_number_of_students(classroom: list[str]):
"""Print the number of students in a classroom"""
if not isinstance(classroom, list):
raise None
print(f"The classroom has {len(classroom)} students.")
#####################
# Attempting to exploit above code example
#####################
print_number_of_students(["student 1", "student 2", "student 3"])
print_number_of_students(None)
This code example returns: TypeError: exceptions must derive from BaseException
. This is problematic because rasing None
does not provide any useful error information or traceback, leading to less informative error handling and potentially causing the program to crash unexpectedly without clear diagnostic details.
The compliant03.py
solution raises a ValueError
rather than None
, ensuring clear error reporting.
# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Compliant Code Example"""
def print_number_of_students(classroom: list[str]):
"""Print the number of students in a classroom"""
if not isinstance(classroom, list):
raise ValueError("classroom is not a list")
# TODO: also check each entry
print(f"The classroom has {len(classroom)} students.")
#####################
# Attempting to exploit above code example
#####################
print_number_of_students(["student 1", "student 2", "student 3"])
print_number_of_students(None)
Tool | Version | Checker | Description |
---|---|---|---|
mypy | 0.960 on python 3.10.4 | Item “None” of “Optional[str]” has no attribute “split” | |
pylint | 3.3.4 | E0702-raising bad-type | Raising NoneType while only classes or instances are allowed |
pyright | 1.1.402 | noncompliant01.py:17:22 - error: Argument of type “None” cannot be assigned to parameter “s” of type “str” in function “is_valid_name” None” is not assignable to “str” (reportArgumentType) noncompliant03.py:21:19 - error: Invalid exception class or object “None” does not derive from BaseException (reportGeneralTypeIssues) 2 errors, 0 warnings, 0 informations | |
pylance | 2025.6.2 | Argument of type “None” cannot be assigned to parameter “s” of type “str” in function “is_valid_name” |
[Python 3.10.4 docs] | The None Object |