The Vyper built-in function raw_call
allows for the kwarg value
if is_delegate_call
is True
. The Vyper compiler must throw in this context as the opcode DELEGATECALL
does not support any CALLVALUE
. Or in other words, the kwarg value
is not added to the IR/bytecode.
Let's make a simple example contract:
The issue here now is that value=msg.value
is allowed while is_delegate_call=True
is also enabled. As comparison, the Solidity compiler would correctly throw in this context with TypeError: Cannot set option "value" for delegatecall
. If you check the compiler internals (e.g. here), you can see the following correct behaviour:
Thus, unfortunately, the compiler implies that this is correct behaviour and people could assume that msg.value
is forwarded (which is not true).
The impact is that people might send ETH to the contract thinking the raw_call
will forward it (from what they can read in the the code (the kwarg)) while instead the ETH stays here. In theory, this could be even used to create a honeypot with verified contracts, implying the users that if they send ETH to the main contract, that it gets forwarded to do some logic, but actually it stays within the proxy and the exploiter can simply withdraw it.
As a simple illustration why it can be problematic I deployed the above code to Goerli: https://goerli.etherscan.io/address/0xb2a04a1e78efa0b46e9e230cb690c9f2a23bf34c#code. I conduct here a simple test tx: https://goerli.etherscan.io/tx/0xbb9ba4b6ea43f39aa80239f2a05fb59039f9d973f9b008774669e378bbaeebe1, where I call the function test
on target
being an EOA, for which I know that it will return success = True
and I could assume that the 0.2 ETH gets forwarded to the EOA. However, this is not the case, and the 0.2 ETH stays within the contract.
It's important to note that I haven't found any on-chain vulnerable contracts fortunately.
A more sophisticated example is where you use a multicall function combined with delegatecall
:
The line msg_value: uint256 = batch.value
is implying a wrong msg.value
for the raw_call
call.
My brain :)
The Vyper compiler must disallow the combination of the kwarg value
and is_delegate_call=True
.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.