Vyper vulnerable to integer overflow in loop
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.
| Package | Affected versions | Patched versions |
|---|---|---|
vyperPyPI | < 0.3.8 | 0.3.8 |
Affected products
1Patches
13de1415ee77aMerge pull request from GHSA-6r8q-pfpv-7cgj
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- github.com/advisories/GHSA-6r8q-pfpv-7cgjghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-32058ghsaADVISORY
- github.com/pypa/advisory-database/tree/main/vulns/vyper/PYSEC-2023-78.yamlghsaWEB
- github.com/vyperlang/vyper/commit/3de1415ee77a9244eb04bdb695e249d3ec9ed868ghsax_refsource_MISCWEB
- github.com/vyperlang/vyper/security/advisories/GHSA-6r8q-pfpv-7cgjghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.