Vyper vulnerable to incorrect ordering of arguments for kwargs passed to internal calls
Description
Vyper is a Pythonic smart contract language for the Ethereum virtual machine. Prior to version 0.3.8, internal calls with default arguments are compiled incorrectly. Depending on the number of arguments provided in the call, the defaults are added not right-to-left, but left-to-right. If the types are incompatible, typechecking is bypassed. The ability to pass kwargs to internal functions is an undocumented feature that is not well known about. The issue is patched in version 0.3.8.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Vyper prior to 0.3.8 incorrectly compiles internal calls with default arguments, potentially bypassing type checking.
Vulnerability
Summary Vyper, a Pythonic smart contract language for the Ethereum Virtual Machine (EVM), contains a compilation flaw in versions prior to 0.3.8. When internal functions are called with default arguments, the compiler incorrectly applies defaults left-to-right instead of the expected right-to-left order. This mishandling can cause type mismatches to be overlooked, bypassing the language's type-checking mechanism [1][3].
Attack
Vector and Exploitation The vulnerability resides in an undocumented feature that allows keyword arguments (kwargs) to be passed to internal functions [1]. An attacker who can influence the arguments supplied to such a function might exploit this ordering defect. Because the feature is not widely known, contracts relying on default arguments in internal calls are at risk if they assume the compiler applies defaults correctly. The attack does not require special network access beyond the ability to interact with the vulnerable smart contract [2][3].
Impact
If successfully exploited, this bug could lead to unexpected behavior in Vyper smart contracts. The bypass of type checking may allow arguments to be interpreted as types incompatible with the function signature, potentially leading to logical errors, fund loss, or other unintended contract states. The severity depends on how the vulnerable contract uses default arguments in internal functions [1][4].
Mitigation
The issue has been patched in Vyper version 0.3.8. Users are advised to upgrade all Vyper compiler installations to this version or later. No workarounds are documented; updating the compiler is the recommended course of action [1][4].
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
1c3e68c302aa6Merge pull request from GHSA-ph9x-4vc9-m39g
2 files changed · +63 −3
tests/parser/features/test_internal_call.py+62 −0 modified@@ -1,6 +1,9 @@ +import string from decimal import Decimal +import hypothesis.strategies as st import pytest +from hypothesis import given, settings from vyper.compiler import compile_code from vyper.exceptions import ArgumentException, CallViolation @@ -642,3 +645,62 @@ def bar() -> String[6]: c = get_contract_with_gas_estimation(contract) assert c.bar() == "hello" + + +# TODO probably want to refactor these into general test utils +st_uint256 = st.integers(min_value=0, max_value=2**256 - 1) +st_string65 = st.text(max_size=65, alphabet=string.printable) +st_bytes65 = st.binary(max_size=65) +st_sarray3 = st.lists(st_uint256, min_size=3, max_size=3) +st_darray3 = st.lists(st_uint256, max_size=3) + +internal_call_kwargs_cases = [ + ("uint256", st_uint256), + ("String[65]", st_string65), + ("Bytes[65]", st_bytes65), + ("uint256[3]", st_sarray3), + ("DynArray[uint256, 3]", st_darray3), +] + + +@pytest.mark.parametrize("typ1,strategy1", internal_call_kwargs_cases) +@pytest.mark.parametrize("typ2,strategy2", internal_call_kwargs_cases) +def test_internal_call_kwargs(get_contract, typ1, strategy1, typ2, strategy2): + # GHSA-ph9x-4vc9-m39g + + @given(kwarg1=strategy1, default1=strategy1, kwarg2=strategy2, default2=strategy2) + @settings(deadline=None, max_examples=5) # len(cases) * len(cases) * 5 * 5 + def fuzz(kwarg1, kwarg2, default1, default2): + code = f""" +@internal +def foo(a: {typ1} = {repr(default1)}, b: {typ2} = {repr(default2)}) -> ({typ1}, {typ2}): + return a, b + +@external +def test0() -> ({typ1}, {typ2}): + return self.foo() + +@external +def test1() -> ({typ1}, {typ2}): + return self.foo({repr(kwarg1)}) + +@external +def test2() -> ({typ1}, {typ2}): + return self.foo({repr(kwarg1)}, {repr(kwarg2)}) + +@external +def test3(x1: {typ1}) -> ({typ1}, {typ2}): + return self.foo(x1) + +@external +def test4(x1: {typ1}, x2: {typ2}) -> ({typ1}, {typ2}): + return self.foo(x1, x2) + """ + c = get_contract(code) + assert c.test0() == [default1, default2] + assert c.test1() == [kwarg1, default2] + assert c.test2() == [kwarg1, kwarg2] + assert c.test3(kwarg1) == [kwarg1, default2] + assert c.test4(kwarg1, kwarg2) == [kwarg1, kwarg2] + + fuzz()
vyper/codegen/context.py+1 −3 modified@@ -267,10 +267,8 @@ def _check(cond, s="Unreachable"): # _check(all(l.typ == r.typ for (l, r) in zip(args_ir, sig.args)) num_provided_kwargs = len(args_ir) - len(sig.base_args) - num_kwargs = len(sig.default_args) - kwargs_needed = num_kwargs - num_provided_kwargs - kw_vals = list(sig.default_values.values())[:kwargs_needed] + kw_vals = list(sig.default_values.values())[num_provided_kwargs:] return sig, kw_vals
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-ph9x-4vc9-m39gghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-32059ghsaADVISORY
- github.com/pypa/advisory-database/tree/main/vulns/vyper/PYSEC-2023-79.yamlghsaWEB
- github.com/vyperlang/vyper/commit/c3e68c302aa6e1429946473769dd1232145822acghsax_refsource_MISCWEB
- github.com/vyperlang/vyper/security/advisories/GHSA-ph9x-4vc9-m39gghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.