CWE-191, Integer Underflow (Wrap or Wraparound)

Ensure that integer overflow is properly handled in order to avoid unexpected behavior. Python data types can be divided into two categories:

Developers should follow the C guidelines when using or interacting wth C type variables.

Non-Compliant Code Example

Using a numpy.int64 can cause an unintentional flip of its sign when reaching the maximum number that can be stored as demonstrated in noncompliant01.py.

noncompliant01.py:

""" Non-compliant Code Example """

import numpy

a = numpy.int64(numpy.iinfo(numpy.int64).max)
print(a + 1)  # RuntimeWarning and continues
print()
b = numpy.int64(numpy.iinfo(numpy.int64).max + 1)  # OverflowError and stops
print(b)  # we will never reach this

Adding +1 to 9223372036854775807 results in a negative number -9223372036854775808 and throws a RuntimeWarning but continues.

An attempt to create int from a too big number causes an OverflowError and stops.

[!NOTE] It has been observed that different results may occur depending on the version of numpy. For reference, we are using numpy 1.23.1 and Python 3.9.12.

Compliant Solution

The compliant01.py code detects the integer overflow by catching the appropriate Exception.

compliant01.py:

""" Compliant Code Example """

import warnings
import numpy

warnings.filterwarnings("error")
a = numpy.int64(numpy.iinfo(numpy.int64).max)
with warnings.catch_warnings():
    try:
        print(a + 1)
    except Warning as _:
        print("Failed to increment " + str(a) + " due to overflow error")
    # RuntimeWarning and continues

try:
    b = numpy.int64(numpy.iinfo(numpy.int64).max + 1)  # OverflowError and stops
except OverflowError as e:
    print("Failed to assign value to B due to overflow error")

Non-Compliant Code Example

The noncompliant02.py example uses datetime.timedelta() to get x hours in the future or past for time travelers. The datetime is interfacing with the operating system through the libpython library written in C. Overall the Georgian calender ISO 8601 is limited to 1 - 9999 years Python datetime 2025.

noncompliant02.py:

# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Noncompliant Code Example"""

from datetime import datetime, timedelta


def get_datetime(currtime: datetime, hours: int):
    """
    Gets the time n hours in the future or past

    Parameters:
    currtime (datetime): A datetime object with the starting datetime.
    hours (int): Hours going forward or backwards

    Returns:
    datetime: A datetime object
    """
    return currtime + timedelta(hours=hours)


#####################
# attempting to exploit above code example
#####################
datetime.fromtimestamp(0)
currtime = datetime.fromtimestamp(1)  # 1st Jan 1970

# OK values are expected to work
# NOK values trigger OverflowErrors in libpython written in C
hours_list = [
    0,  # OK
    1,  # OK
    70389526,  # OK
    70389527,  # NOK
    51539700001,  # NOK
    24000000001,  # NOK
    -1,  # OK
    -17259889,  # OK
    -17259890,  # NOK
    -23999999999,  # NOK
    -51539699999,  # NOK
]
for hours in hours_list:
    try:
        result = get_datetime(currtime, hours)
        print(f"{hours} OK, datetime='{result}'")
    except Exception as exception:
        print(f"{hours} {repr(exception)}")

The noncompliant02.py code is triggering various OverflowError exceptions in the libpython library:

Compliant Solution

This compliant02.py solution is preventing OverflowError exception in libpython by safeguarding the upper and lower limits in the provided hours. Upper and lower limit for currtime as well as input sanitization and secure logging are missing and must be added when interfacing with a lesser trusted entity.

compliant02.py:

# SPDX-FileCopyrightText: OpenSSF project contributors
# SPDX-License-Identifier: MIT
"""Compliant Code Example"""

from datetime import datetime, timedelta
import logging

# Enabling verbose debugging
# logging.basicConfig(level=logging.DEBUG)


def get_datetime(currtime: datetime, hours: int):
    """
    Gets the time n hours in the future or past

    Parameters:
    currtime (datetime): A datetime object with the starting datetime.
    hours (int): Hours going forward or backwards

    Returns:
    datetime: A datetime object
    """
    # TODO: input sanitation
    # Calculate lower boundary, hours from year 1 to currtime:
    timedelta_lowerbound = currtime - datetime(1, 1, 1)  # 1st Jan 0001
    hours_min = timedelta_lowerbound.total_seconds() // 3600 * -1

    # Calculate upper boundary, hours from year 9999 to currtime:
    timedelta_upperbound = datetime(9999, 12, 31) - currtime
    hours_max = timedelta_upperbound.total_seconds() // 3600

    # TODO: proper secure logging
    logging.debug(
        "hours_max=%s hours_min=%s hours=%s",
        hours_max,
        hours_min,
        hours,
    )
    if (hours > hours_max) or (hours < hours_min):
        raise ValueError("hours out of range")

    return currtime + timedelta(hours=hours)


#####################
# attempting to exploit above code example
#####################
datetime.fromtimestamp(0)
currtime = datetime.fromtimestamp(1)  # 1st Jan 1970

# OK values are expected to work
# NOK values trigger OverflowErrors in libpython written in C
hours_list = [
    0,  # OK
    1,  # OK
    70389526,  # OK
    70389527,  # NOK
    51539700001,  # NOK
    24000000001,  # NOK
    -1,  # OK
    -17259889,  # OK
    -17259890,  # NOK
    -23999999999,  # NOK
    -51539699999,  # NOK
]
for hours in hours_list:
    try:
        result = get_datetime(currtime, hours)
        print(f"{hours} OK, datetime='{result}'")
    except Exception as exception:
        print(f"{hours} {repr(exception)}")

The compliant02.py example is protecting the lower level c-lib from an OverflowError by setting boundaries for valid values in hours. Similar issues occure with any functionality provided through the operating system.

Non-Compliant Code Example

The noncompliant03.py code example results in a OverflowError: math range error. This is due to math.exp being a C implementation behind the scenes for better performance. So while it returns a Python float it does use C type of variables internally for the calculation in mathmodule.c [cpython 2024].

noncompliant03.py:

""" Non-compliant Code Example """

import math


def calculate_exponential_value(number):
    """Return 'E' raised to the power of different numbers:"""
    return math.exp(number)


#####################
# attempting to exploit above code example
#####################
print(calculate_exponential_value(1000))

Compliant Solution

This compliant03.py solution detects the integer overflow by catching the appropriate Exception on overflow:

compliant03.py:

""" Compliant Code Example """
import math


def calculate_exponential_value(number):
    """Return 'E' raised to the power of different numbers:"""
    try:
        return math.exp(number)
    except OverflowError as _:
        return "Number " + str(number) + " caused an integer overflow"


#####################
# attempting to exploit above code example
#####################
print(calculate_exponential_value(710))
   
SEI CERT C Coding Standard INT32-C. Ensure that operations on signed integers do not result in overflow
SEI CERT Coding Standard for Java NUM00-J. Detect or prevent integer overflow
ISO/IEC TR 24772:2010 Wrap-around Error [XYY]
MITRE CWE Pillar CWE-682: Incorrect Calculation
MITRE CWE Base CWE-191, Integer Underflow (Wrap or Wraparound)
MITRE CWE Base CWE-190, Integer Overflow or Wraparound

Bibliography

   
[Python 2024] Format String Syntax. [online] Available from: https://docs.python.org/3.9/library/stdtypes.html [Accessed 20 June 2024]
[cpython 2024] mathmodule.c. [online] Available from: https://github.com/python/cpython/blob/main/Modules/mathmodule.c) [Accessed 20 June 2024]
[Python datetime 2025] datetime strftime() and strptime() Format Codes [online], Available from: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes [Accessed 27 March 2025]