CVE-2024-32646
Executive Summary
CVE-2024-32646 is a medium-severity vulnerability in the Vyper smart contract language (versions 0.3.10 and prior) that allows a double evaluation of side-effects when using the slice builtin with specific buffer arguments (msg.data, self.code, or <address>.code) and side-effect-bearing start or length arguments. This can lead to unexpected behavior in smart contracts, potentially enabling attackers to manipulate contract state or cause denial-of-service conditions. The vulnerability is considered low impact as no vulnerable production contracts have been found, and double evaluation of side-effects is easily detectable in client tests. No 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
This vulnerability affects the Vyper compiler itself, which is distributed as a Python package via PyPI. Developers using Vyper to write smart contracts should ensure they are using the latest version of the compiler and monitor for updates. The Vyper compiler is a critical component in the Ethereum smart contract development supply chain, and any vulnerability in it can affect all contracts compiled with the affected version.
CVSS Breakdown & Threat Level
CVSS Score: 5.3 (Medium)
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
Breakdown:
- Attack Vector (AV): Network - The vulnerability can be exploited remotely via crafted transactions.
- Attack Complexity (AC): Low - No special conditions are required for exploitation.
- Privileges Required (PR): None - No authentication needed.
- User Interaction (UI): None - No user action required.
- Scope (S): Unchanged - The vulnerability does not affect other components.
- Confidentiality (C): None - No data disclosure.
- Integrity (I): None - No data modification.
- Availability (A): Low - Potential for denial-of-service or unexpected contract behavior.
Threat Level: Medium - While the CVSS score is moderate, the actual risk is low due to the lack of known vulnerable production contracts and the ease of detection in testing.
Deep Dive & Mechanics
The vulnerability lies in the Vyper compiler's handling of the slice builtin function. When slice is called with a buffer argument that is either msg.data, self.code, or <address>.code, and either the start or length arguments contain side-effects (e.g., function calls that modify state), the compiler may evaluate those side-effects twice instead of once.
This double evaluation occurs because the compiler generates code that accesses the buffer's length or other properties multiple times, each time re-evaluating the side-effect-bearing arguments. In versions prior to 0.3.4, this is easily triggered because the compiler lacks the "unique symbol fence" that prevents such double evaluation. In versions 0.3.4 to 0.3.10, the vulnerability is harder to trigger but still possible under specific conditions.
The impact is that a smart contract using slice with side-effect-bearing arguments could behave unexpectedly, potentially allowing an attacker to manipulate contract state or cause a denial-of-service condition. However, the vulnerability is considered low impact because:
- No vulnerable production contracts have been found.
- Double evaluation of side-effects is easily detectable in client tests.
- The conditions required for exploitation are relatively specific.
Vulnerable vs. Patched Code
Vulnerable Code (Vyper < 0.3.10):
@external
def vulnerable_function(data: Bytes[100]) -> Bytes[50]:
# This could trigger double evaluation if start or length have side-effects
return slice(msg.data, self.get_start(), self.get_length())
In this example, self.get_start() and self.get_length() are functions that may have side-effects (e.g., modifying state variables). In vulnerable versions, these functions may be called twice, leading to unexpected behavior.
Patched Code (Hypothetical fix):
@external
def patched_function(data: Bytes[100]) -> Bytes[50]:
# Evaluate side-effects once and store in local variables
start: uint256 = self.get_start()
length: uint256 = self.get_length()
return slice(msg.data, start, length)
The fix involves ensuring that side-effect-bearing arguments are evaluated only once before being passed to slice. This can be achieved by storing the results in local variables or by modifying the compiler to generate code that evaluates arguments only once.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Vyper compiler version 0.3.10 or prior
- A smart contract that uses
slicewithmsg.data,self.code, or<address>.codeand side-effect-bearingstartorlengtharguments - An Ethereum testnet or local development environment (e.g., Ganache, Hardhat)
Exploitation Steps:
- Deploy a vulnerable Vyper contract that uses
slicewith side-effect-bearing arguments. - Craft a transaction that calls the vulnerable function with specific inputs to trigger the double evaluation.
- Observe the unexpected behavior, such as state changes occurring twice or incorrect data being returned.
Example Exploit Contract:
# Vulnerable contract
@external
def exploit() -> bool:
# This function has a side-effect (incrementing a counter)
self.counter += 1
return True
@external
def vulnerable_slice() -> Bytes[50]:
# The side-effect in exploit() will be evaluated twice
return slice(msg.data, self.exploit(), 10)
Expected Outcome: The self.counter variable will be incremented twice instead of once, demonstrating the double evaluation vulnerability.
Blue Team
Detection:
- Static Analysis: Use Vyper compiler warnings or static analysis tools to detect the use of
slicewith side-effect-bearing arguments. - Dynamic Analysis: Deploy contracts on a testnet and monitor for unexpected state changes or gas consumption patterns.
- Code Review: Manually review smart contract code for the use of
slicewith function calls as arguments.
Mitigation:
- Update Compiler: Monitor for patches and update to the latest Vyper version when available.
- Code Hardening: Avoid using side-effect-bearing arguments with
slice. Instead, evaluate them first and store in local variables. - Testing: Thoroughly test contracts for double evaluation issues using unit tests and fuzzing.
Indicators of Compromise (IOCs)
- Contract Behavior: Unexpected state changes (e.g., counters incrementing twice) when using
slicewith function calls as arguments. - Gas Consumption: Higher than expected gas usage due to double evaluation of side-effects.
- Compiler Warnings: Vyper compiler may not produce warnings for this vulnerability in affected versions.
Detection Engineering
YARA Rule
rule CVE_2024_32646_Vyper_Slice_Double_Eval {
meta:
description = "Detects Vyper smart contracts vulnerable to CVE-2024-32646 double evaluation in slice"
author = "Valters IT"
date = "2024-01-01"
cve = "CVE-2024-32646"
strings:
$slice_pattern = /slice\s*\(\s*(msg\.data|self\.code|<address>\.code)\s*,/ nocase
$function_call = /self\.\w+\s*\(/
condition:
$slice_pattern and #function_call > 0
}
Sigma Rule
title: CVE-2024-32646 Vyper Slice Double Evaluation
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects potential exploitation of CVE-2024-32646 in Vyper smart contracts
author: Valters IT
date: 2024-01-01
logsource:
category: smart_contract
product: ethereum
detection:
selection:
contract_code|contains:
- 'slice(msg.data'
- 'slice(self.code'
- 'slice(<address>.code'
condition: selection
falsepositives:
- Legitimate use of slice with constant arguments
level: medium
Suricata Rule
alert ip any any -> any any (msg:"CVE-2024-32646 Vyper Slice Double Evaluation Attempt"; content:"slice"; content:"msg.data"; distance:0; within:100; content:"self."; distance:0; within:50; classtype:attempted-exploit; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Code Review: Review all Vyper smart contracts for the use of
slicewith side-effect-bearing arguments. - Code Hardening: Refactor vulnerable code to evaluate side-effects before calling
slice. - Testing: Run comprehensive tests to detect double evaluation issues.
Long-term Fix:
- Update Compiler: Monitor the Vyper project for a patched version and update as soon as it becomes available.
- Static Analysis: Integrate static analysis tools into the CI/CD pipeline to detect this vulnerability automatically.
Workarounds:
- Avoid using
slicewithmsg.data,self.code, or<address>.codewhen thestartorlengtharguments contain function calls. - Use local variables to store the results of side-effect-bearing expressions before passing them to
slice.
Valters IT