CVE-2025-21607
Executive Summary
CVE-2025-21607 is a vulnerability in the Vyper smart contract compiler, a Pythonic language for the Ethereum Virtual Machine (EVM). The flaw arises when the compiler generates code that calls the EVM precompiles EcRecover (address 0x1) and Identity (address 0x4). The compiler fails to check the success flag of these calls. An attacker can supply a specific amount of gas to cause these precompile calls to fail silently, while allowing the overall contract execution to continue. This can lead to incorrect execution results, potentially bypassing security checks that rely on the output of these precompiles (e.g., signature verification via EcRecover). The impact is limited because, per EVM rules, after a failed precompile call, only 1/64 of the original gas remains, restricting the complexity of subsequent code. The advisory was issued out of an abundance of caution, and no significantly impacted real-world contracts were found. The vulnerability is fixed in Vyper version 0.4.1.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects the Vyper compiler itself, which is a development tool used to compile smart contracts. It is not a runtime vulnerability in deployed contracts but a compiler-level bug. Developers using Vyper versions prior to 0.4.1 are at risk of generating contracts that may behave incorrectly under specific gas conditions. The Vyper compiler is distributed via PyPI (vyper package) and GitHub. Users should update their compiler to the patched version and recompile any contracts that use EcRecover or Identity precompiles.
CVSS Breakdown & Threat Level
- CVSS Score: 0.0 (NVD assigned, likely due to limited impact)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
- Attack Vector: Network (attacker can craft a transaction with specific gas)
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: None
- Integrity Impact: Low (potential for incorrect execution results)
- Availability Impact: None
- Threat Level: Low (due to gas constraints limiting exploitability)
Deep Dive & Mechanics
The vulnerability is rooted in the Vyper compiler's code generation for calls to EVM precompiles. In the EVM, precompiled contracts at addresses 0x01 (EcRecover) and 0x04 (Identity) perform specific cryptographic operations. When a contract calls a precompile, the EVM forwards gas and expects a success flag. If the precompile fails (e.g., due to insufficient gas), the success flag is set to 0, and the call returns an empty result.
The Vyper compiler, in versions prior to 0.4.1, did not check this success flag. It assumed the call always succeeded. An attacker can craft a transaction that provides exactly enough gas to make the precompile call fail (e.g., by setting gas to a value that causes the precompile to run out of gas), but still leaves enough gas for the rest of the contract to execute (though only 1/64 of the original gas remains). This can lead to scenarios where:
- EcRecover: A signature verification returns an incorrect address (e.g., zero address) because the precompile failed, but the contract continues execution as if the signature was valid.
- Identity: A data copy operation returns an empty or incorrect result, potentially corrupting state.
The gas limitation (1/64 of original gas) severely restricts the complexity of code that can follow the failed call, making it difficult to exploit in complex contracts. However, simple contracts with minimal post-call logic could be affected.
Vulnerable vs. Patched Code
Vulnerable Code (Vyper < 0.4.1): The compiler generated code similar to:
# Pseudocode for vulnerable Vyper compilation
success = call_precompile(0x01, gas, input, output)
# success flag is NOT checked
# output is used directly, even if precompile failed
Patched Code (Vyper 0.4.1): The compiler now checks the success flag:
# Pseudocode for patched Vyper compilation
success = call_precompile(0x01, gas, input, output)
if not success:
revert() # or handle failure appropriately
# output is only used if precompile succeeded
The fix ensures that if a precompile call fails, the contract reverts or handles the failure, preventing incorrect state changes.
Exploitation & Lab Setup
Red Team (Attacker)
Prerequisites:
- A target contract compiled with Vyper < 0.4.1 that uses
EcRecoverorIdentityprecompile. - Ability to craft a transaction with specific gas parameters.
Exploitation Steps:
- Identify a Vyper contract that uses
ecdsa_recover(which internally calls EcRecover) oridentityprecompile. - Calculate the exact gas required to make the precompile call fail but leave enough gas for the rest of the contract to execute (1/64 of original gas).
- Craft a transaction with the calculated gas limit.
- Submit the transaction. The precompile call fails, but the contract continues execution, potentially accepting invalid signatures or data.
Example (Conceptual):
# Attacker's transaction
tx = {
"to": target_contract,
"data": "0x...", # function call that uses EcRecover
"gas": 50000, # specific gas to cause precompile failure
}
Note: No public exploit code is available. This is a conceptual attack.
Blue Team (Defender)
Detection:
- Monitor for transactions that call Vyper contracts with unusually low gas limits, especially those involving
ecrecoveroridentityoperations. - Analyze contract bytecode for missing success checks on precompile calls.
Mitigation:
- Recompile all Vyper contracts with version 0.4.1 or later.
- Review contract logic to ensure that precompile call failures are handled correctly.
- Implement gas monitoring to detect anomalous gas usage patterns.
Indicators of Compromise (IOCs)
- Contract Bytecode: Bytecode generated by Vyper < 0.4.1 that contains calls to precompiles
0x01or0x04without subsequent success checks. - Transaction Patterns: Transactions with gas limits that are just enough to cause precompile failure but allow contract continuation.
- EVM Opcodes: Presence of
CALLopcode to addresses0x01or0x04withoutISZEROorJUMPIchecks on the return value.
Detection Engineering
YARA Rule
rule Vyper_Precompile_Success_Check_Missing {
meta:
description = "Detects Vyper compiled bytecode missing success check on EcRecover or Identity precompile calls"
author = "Valters IT"
date = "2025-01-01"
cve = "CVE-2025-21607"
strings:
$precompile_ec = { 60 01 } // PUSH1 0x01 (EcRecover address)
$precompile_id = { 60 04 } // PUSH1 0x04 (Identity address)
$call_opcode = { f1 } // CALL opcode
$success_check = { 15 } // ISZERO opcode (check for success)
condition:
($precompile_ec or $precompile_id) and $call_opcode and not $success_check
}
Sigma Rule
title: Vyper Precompile Call Without Success Check
id: 8a9b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
status: experimental
description: Detects transactions to Vyper contracts that call precompiles without checking success
author: Valters IT
date: 2025-01-01
logsource:
category: blockchain
product: ethereum
detection:
selection:
to_contract: "*" # Replace with specific contract address if known
input|contains: "0x01" or "0x04" # Precompile addresses in call data
condition: selection
falsepositives:
- Legitimate contracts that handle precompile failures differently
level: low
Suricata Rule
alert ip any any -> any any (msg:"CVE-2025-21607 - Vyper Precompile Call Without Success Check"; content:"|60 01|"; content:"|f1|"; within:10; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Update Vyper Compiler: Upgrade to Vyper version 0.4.1 or later.
- Recompile Contracts: Recompile all smart contracts that use
EcRecoverorIdentityprecompiles with the patched compiler. - Verify Bytecode: Ensure the new bytecode includes success checks on precompile calls.
Long-Term Measures:
- Implement automated CI/CD checks to verify that compiled bytecode includes proper error handling for precompile calls.
- Monitor Vyper security advisories for future updates.
- Consider using static analysis tools to detect missing success checks in compiled contracts.
Workarounds:
- If upgrading is not immediately possible, manually add success checks in Vyper code using
assertorifstatements after precompile calls (though this may not be straightforward due to compiler limitations).
Valters IT
DevSecOps & Cyber Threat Intelligence Expert