Vyper's ecrecover can return undefined data if signature does not verify
Description
Vyper is a Pythonic programming language that targets the Ethereum Virtual Machine (EVM). Prior to version 0.3.10, the ecrecover precompile does not fill the output buffer if the signature does not verify. However, the ecrecover builtin will still return whatever is at memory location 0. This means that the if the compiler has been convinced to write to the 0 memory location with specially crafted data (generally, this can happen with a hashmap access or immutable read) just before the ecrecover, a signature check might pass on an invalid signature. Version 0.3.10 contains a patch for this issue.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Vyper versions before 0.3.10 have an ecrecover vulnerability where invalid signatures can return attacker-controlled memory, bypassing verification.
Vulnerability
Detail The ecrecover precompile in Vyper (prior to v0.3.10) does not write to the output buffer when a signature fails verification. However, the ecrecover builtin returns the contents of memory location 0. If an attacker can arrange for attacker-controlled data to be at memory location 0—for example via a hashmap access or immutable read—the signature check may incorrectly pass on an invalid signature [1][4].
Exploitation
The exploit requires the ability to write to memory location 0 before the ecrecover call. This can happen if the compiler places a hashmap value or an immutable at that location. In practice, many contracts (e.g., ERC2612 permit implementations) are not vulnerable because they read a constant like PERMIT_TYPEHASH before ecrecover, which is not a valid address. However, if an immutable representing a real address (e.g., an owner) is read just before ecrecover, an attacker could craft an invalid signature that returns that address, passing the check [4].
Impact
An attacker could forge signature verification, leading to unauthorized actions such as token transfers or state changes that rely on ecrecover for authorization. This could compromise contract security if the vulnerable pattern is used [1][4].
Mitigation
The issue is patched in Vyper v0.3.10. Users should upgrade immediately. No workaround is available beyond refactoring code to avoid the vulnerable pattern [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.10 | 0.3.10 |
Affected products
1Patches
1019a37ab98ffMerge pull request from GHSA-f5x6-7qgp-jhf3
2 files changed · +28 −20
tests/parser/functions/test_ecrecover.py+18 −0 modified@@ -40,3 +40,21 @@ def test_ecrecover_uints2() -> address: assert c.test_ecrecover_uints2() == local_account.address print("Passed ecrecover test") + + +def test_invalid_signature(get_contract): + code = """ +dummies: HashMap[address, HashMap[address, uint256]] + +@external +def test_ecrecover(hash: bytes32, v: uint8, r: uint256) -> address: + # read from hashmap to put garbage in 0 memory location + s: uint256 = self.dummies[msg.sender][msg.sender] + return ecrecover(hash, v, r, s) + """ + c = get_contract(code) + hash_ = bytes(i for i in range(32)) + v = 0 # invalid v! ecrecover precompile will not write to output buffer + r = 0 + # note web3.py decoding of 0x000..00 address is None. + assert c.test_ecrecover(hash_, v, r) is None
vyper/builtins/functions.py+10 −20 modified@@ -764,29 +764,19 @@ def infer_arg_types(self, node): @process_inputs def build_IR(self, expr, args, kwargs, context): - placeholder_node = IRnode.from_list( - context.new_internal_variable(BytesT(128)), typ=BytesT(128), location=MEMORY - ) + input_buf = context.new_internal_variable(get_type_for_exact_size(128)) + output_buf = MemoryPositions.FREE_VAR_SPACE return IRnode.from_list( [ "seq", - ["mstore", placeholder_node, args[0]], - ["mstore", ["add", placeholder_node, 32], args[1]], - ["mstore", ["add", placeholder_node, 64], args[2]], - ["mstore", ["add", placeholder_node, 96], args[3]], - [ - "pop", - [ - "staticcall", - ["gas"], - 1, - placeholder_node, - 128, - MemoryPositions.FREE_VAR_SPACE, - 32, - ], - ], - ["mload", MemoryPositions.FREE_VAR_SPACE], + # clear output memory first, ecrecover can return 0 bytes + ["mstore", output_buf, 0], + ["mstore", input_buf, args[0]], + ["mstore", input_buf + 32, args[1]], + ["mstore", input_buf + 64, args[2]], + ["mstore", input_buf + 96, args[3]], + ["staticcall", "gas", 1, input_buf, 128, output_buf, 32], + ["mload", output_buf], ], typ=AddressT(), )
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-f5x6-7qgp-jhf3ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-37902ghsaADVISORY
- github.com/pypa/advisory-database/tree/main/vulns/vyper/PYSEC-2023-133.yamlghsaWEB
- github.com/vyperlang/vyper/commit/019a37ab98ff53f04fecfadf602b6cd5ac748f7fghsax_refsource_MISCWEB
- github.com/vyperlang/vyper/security/advisories/GHSA-f5x6-7qgp-jhf3ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.