VYPR
High severityNVD Advisory· Published May 11, 2023· Updated Jan 24, 2025

Vyper vulnerable to integer overflow in loop

CVE-2023-32058

Description

Vyper is a Pythonic smart contract language for the Ethereum virtual machine. Prior to version 0.3.8, due to missing overflow check for loop variables, by assigning the iterator of a loop to a variable, it is possible to overflow the type of the latter. The issue seems to happen only in loops of type for i in range(a, a + N) as in loops of type for i in range(start, stop) and for i in range(stop), the compiler is able to raise a TypeMismatch when trying to overflow the variable. The problem has been patched in version 0.3.8.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Vyper <0.3.8 missing overflow check for loop variables allows type overflow via iterator assignment in range loops.

Vulnerability

Overview

CVE-2023-32058 is an integer overflow vulnerability in the Vyper smart contract compiler for the Ethereum Virtual Machine (EVM). Prior to version 0.3.8, the compiler did not properly check for overflow when a loop iterator variable was assigned to another variable within certain for loop structures. Specifically, the issue manifests in loops of the form for i in range(a, a + N), where the iterator i can overflow the type of the variable it is assigned to [1][4]. The compiler correctly raises a TypeMismatch error for for i in range(start, stop) and for i in range(stop) forms when such overflow is attempted, but this check was missing for the dynamic-range variant [1].

Attack

Vector and Exploitation

To exploit this, a developer writes Vyper code that includes a for loop with a dynamically computed start and end (e.g., range(a, a+N)) and assigns the loop iterator to a variable with a specific integer type (e.g., uint8, int128, uint256). By crafting the loop bounds such that the iterator exceeds the maximum value of that type, an overflow occurs silently during compilation, resulting in incorrect arithmetic or unexpected behavior at runtime. No authentication or network access is needed; the vulnerability is triggered during contract compilation when the source code is processed by the Vyper compiler [1][4].

Impact

An attacker who can influence the loop bounds (e.g., via user-supplied inputs or state variables used in range()) could cause overflow of the assigned variable's type. This can lead to incorrect loop iteration counts, unintended logical errors, or underflow/overflow conditions that may be exploited to manipulate contract state, bypass access controls, or cause denial of service. The precise impact is context-dependent, but any such bug can undermine the contract's intended behavior and security guarantees.

Mitigation

The issue has been patched in Vyper version 0.3.8. The fix introduces a clamping operation (clamp) on the start value of the loop to ensure it does not exceed the allowed bounds of the variable type, preventing overflow [4]. Developers are strongly advised to upgrade to Vyper 0.3.8 or later. No workaround exists for older versions other than avoiding the vulnerable loop pattern or applying manual safe-math checks in contract code. The vulnerability is not currently listed in CISA's KEV as of the publication date [1].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
vyperPyPI
< 0.3.80.3.8

Affected products

1

Patches

1
3de1415ee77a

Merge pull request from GHSA-6r8q-pfpv-7cgj

https://github.com/vyperlang/vyperCharles CooperMay 11, 2023via ghsa
2 files changed · +42 0
  • tests/parser/features/iteration/test_for_range.py+39 0 renamed
    @@ -128,6 +128,45 @@ def foo(a: {typ}) -> {typ}:
         assert c.foo(100) == 31337
     
     
    +# test that we can get to the upper range of an integer
    +@pytest.mark.parametrize("typ", ["uint8", "int128", "uint256"])
    +def test_for_range_edge(get_contract, typ):
    +    code = f"""
    +@external
    +def test():
    +    found: bool = False
    +    x: {typ} = max_value({typ})
    +    for i in range(x, x + 1):
    +        if i == max_value({typ}):
    +            found = True
    +
    +    assert found
    +
    +    found = False
    +    x = max_value({typ}) - 1
    +    for i in range(x, x + 2):
    +        if i == max_value({typ}):
    +            found = True
    +
    +    assert found
    +    """
    +    c = get_contract(code)
    +    c.test()
    +
    +
    +@pytest.mark.parametrize("typ", ["uint8", "int128", "uint256"])
    +def test_for_range_oob_check(get_contract, assert_tx_failed, typ):
    +    code = f"""
    +@external
    +def test():
    +    x: {typ} = max_value({typ})
    +    for i in range(x, x+2):
    +        pass
    +    """
    +    c = get_contract(code)
    +    assert_tx_failed(lambda: c.test())
    +
    +
     @pytest.mark.parametrize("typ", ["int128", "uint256"])
     def test_return_inside_nested_repeater(get_contract, typ):
         code = f"""
    
  • vyper/codegen/stmt.py+3 0 modified
    @@ -10,6 +10,7 @@
         IRnode,
         append_dyn_array,
         check_assign,
    +    clamp,
         dummy_node_for_type,
         get_dyn_array_count,
         get_element_ptr,
    @@ -264,6 +265,8 @@ def _parse_For_range(self):
                 arg1 = self.stmt.iter.args[1]
                 rounds = self._get_range_const_value(arg1.right)
                 start = Expr.parse_value_expr(arg0, self.context)
    +            _, hi = start.typ.int_bounds
    +            start = clamp("le", start, hi + 1 - rounds)
     
             r = rounds if isinstance(rounds, int) else rounds.value
             if r < 1:
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.