CVE-2024-24567
Executive Summary
CVE-2024-24567 is a medium-severity vulnerability in the Vyper smart contract compiler (versions 0.3.10 and earlier). The flaw lies in the raw_call built-in function, which allows a value parameter to be passed even when the call is a delegatecall or staticcall. Due to the semantics of the EVM opcodes for delegatecall and staticcall, the value argument is silently ignored. This can lead to a discrepancy between developer intent and actual contract behavior, potentially resulting in financial loss or unexpected state changes. The vulnerability has a CVSS score of 4.8 (Medium) and an EPSS score of 0.0%, indicating low exploitation likelihood in the wild. No public exploit code or patch is currently available.
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
Vyper is a Python-based smart contract language for the Ethereum Virtual Machine (EVM). It is distributed via PyPI as the vyper package. Developers using Vyper to compile smart contracts are affected. The vulnerability is in the compiler itself, meaning any contract compiled with a vulnerable version may contain the flaw. Supply chain risk is moderate, as the compiler is a development tool; however, deployed contracts cannot be easily patched without redeployment.
CVSS Breakdown & Threat Level
- CVSS Score: 4.8 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: None
- Integrity Impact: Low
- Availability Impact: None
The low integrity impact reflects that the vulnerability can cause unintended behavior (e.g., missing value transfer) but does not allow direct data theft or denial of service.
Deep Dive & Mechanics
The Vyper compiler's raw_call built-in function is designed to perform low-level EVM calls. It accepts a value keyword argument to specify the amount of Ether to send with the call. However, when the call type is delegatecall or staticcall, the EVM opcodes for these operations do not support value transfer. The Vyper compiler fails to validate or reject the value parameter in these contexts, silently ignoring it.
Technical Details:
- In EVM,
CALLopcode can transfer Ether, butDELEGATECALLandSTATICCALLcannot. - Vyper's
raw_callwithdelegate_call=Trueorstatic_call=Truecompiles toDELEGATECALLorSTATICCALLrespectively. - The
valueargument is parsed but not used in the generated bytecode for these call types. - A developer unaware of this limitation may write code like:
expecting 1 ETH to be sent, but no Ether is transferred.raw_call(target, data, value=1 ether, delegate_call=True)
Impact: This can lead to:
- Failed business logic (e.g., payment not received).
- Unexpected contract state if the called contract relies on receiving Ether.
- Potential for attackers to exploit the discrepancy if they can influence the call parameters.
Vulnerable vs. Patched Code
Vulnerable Code (Vyper <= 0.3.10):
@external
def vulnerable_call(target: address, data: Bytes[1024]):
raw_call(target, data, value=1 ether, delegate_call=True)
# Developer expects 1 ETH to be sent, but it is not.
Patched Code (Vyper 0.3.11+):
@external
def patched_call(target: address, data: Bytes[1024]):
# Compiler now rejects value with delegatecall/staticcall
# raw_call(target, data, value=1 ether, delegate_call=True) # Compilation error
raw_call(target, data, delegate_call=True) # No value argument allowed
The patch adds a compile-time check that raises an error if value is provided with delegate_call=True or static_call=True.
Exploitation & Lab Setup
Red Team
Exploitation Scenario:
- Identify a Vyper contract compiled with version <= 0.3.10 that uses
raw_callwithdelegate_call=Trueand a non-zerovalue. - Craft a call to the vulnerable function that triggers the
raw_callwith avalueargument. - Observe that no Ether is transferred, potentially causing the contract to behave incorrectly (e.g., failing to pay for a service).
- If the called contract expects Ether and performs actions based on
msg.value, the attacker can exploit the discrepancy to bypass payment requirements.
Lab Setup:
- Use a local Ethereum testnet (e.g., Ganache) with Vyper 0.3.10 installed.
- Deploy a vulnerable contract and a target contract that logs
msg.value. - Execute the vulnerable function and verify that
msg.valueis 0 despite thevalueargument.
Example Exploit (Python with web3.py):
from web3 import Web3
w3 = Web3(Web3.HTTPProvider('http://localhost:8545'))
vulnerable_contract = w3.eth.contract(address='0x...', abi=[...])
tx_hash = vulnerable_contract.functions.vulnerable_call('0x...', b'').transact({'value': w3.to_wei(1, 'ether')})
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
# Check target contract logs to see msg.value was 0
Blue Team
Detection:
- Monitor for transactions that call functions using
raw_callwithdelegate_call=Trueorstatic_call=Trueand a non-zerovalueparameter. - Analyze contract bytecode for patterns indicating the vulnerability (e.g.,
DELEGATECALLopcode with a precedingCALLVALUEthat is ignored).
Mitigation:
- Upgrade Vyper compiler to version 0.3.11+.
- Recompile and redeploy affected contracts.
- Perform code review to ensure no
raw_callwithvalueis used for delegate/static calls.
Indicators of Compromise (IOCs)
- Contract Bytecode Pattern: Presence of
DELEGATECALLorSTATICCALLopcode in a function that also has aCALLVALUEopcode that is not consumed. - Transaction Pattern: Transactions to contracts compiled with Vyper <= 0.3.10 that include a
valuefield but the called function usesdelegate_call=True. - Compiler Version: Vyper compiler version 0.3.10 or earlier in the build artifacts.
Detection Engineering
YARA Rule
rule Detect_Vyper_RawCall_Value_Delegate {
meta:
description = "Detects Vyper bytecode with raw_call value in delegatecall/staticcall"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2024-24567"
strings:
$opcode_delegatecall = { DELEGATECALL }
$opcode_staticcall = { STATICCALL }
$opcode_callvalue = { CALLVALUE }
condition:
($opcode_delegatecall or $opcode_staticcall) and $opcode_callvalue
}
Sigma Rule
title: Vyper Raw Call Value in Delegate/Static Call
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects transactions to Vyper contracts with potential CVE-2024-24567 exploitation
author: Valters IT
date: 2025-04-10
logsource:
category: blockchain
product: ethereum
detection:
selection:
to_contract_compiler: "vyper"
compiler_version: "<=0.3.10"
function_uses_raw_call: true
raw_call_has_value: true
call_type: "delegatecall" or "staticcall"
condition: selection
falsepositives:
- Legitimate use where value is intentionally ignored (unlikely)
level: medium
Suricata Rule
alert ip any any -> any any (msg:"CVE-2024-24567 Vyper Raw Call Value in Delegate/Static Call"; content:"|DELEGATECALL|"; content:"|CALLVALUE|"; distance:0; within:10; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade Vyper compiler to version 0.3.11 or later as soon as it is released.
- Recompile all smart contracts that use
raw_callwithdelegate_call=Trueorstatic_call=True. - Review contract code to ensure no
valueargument is passed toraw_callfor delegate/static calls.
Long-term Measures:
- Implement static analysis tools to detect this pattern in Vyper code.
- Educate developers on EVM opcode semantics and Vyper's built-in functions.
- Monitor Vyper release notes for security patches.
Workaround:
- If upgrade is not possible, manually audit all
raw_callusages and removevaluearguments for delegate/static calls.
Valters IT