Platform: Code4rena
Start Date: 06/06/2023
Pot Size: $60,500 USDC
Total HM: 5
Participants: 50
Period: 8 days
Judge: gzeon
Id: 246
League: ETH
Rank: 28/50
Findings: 1
Award: $54.53
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: libratus
Also found by: 0xcm, BRONZEDISC, Co0nan, Go-Langer, Madalad, MiniGlome, QiuhaoLi, T1MOH, Toshii, Udsen, ernestognw, flacko, joestakey, minhquanym, n1punp, rvierdiiev, sces60107
54.5276 USDC - $54.53
https://github.com/code-423n4/2023-06-llama/blob/aac904d31639c1b4b4e97f1c76b9c0f40b8e5cee/src/LlamaCore.sol#L334 https://github.com/code-423n4/2023-06-llama/blob/aac904d31639c1b4b4e97f1c76b9c0f40b8e5cee/src/LlamaExecutor.sol#L34
When the executeAction
calls the executor the msg.value
is not pass to the executor contract. Resulting in the executor not having the founds needed by the action.
The execute
function of the LlamaExecutor
is not even payable
but will try to send value
to the target
, which will always fail if value > 0 because there is no ETH in the smart contract.
File: LlamaExecutor.sol L34: (success, result) = isScript ? target.delegatecall(data) : target.call{value: value}(data);
Here is a foundry test to reproduce the bug
function test_ExecuteWithMsgValue() public { uint256 value = 3 ether; bytes memory data = abi.encodeCall(MockProtocol.receiveEth, ()); vm.prank(actionCreatorAaron); uint256 actionId = mpCore.createAction(uint8(Roles.ActionCreator), mpStrategy1, address(mockProtocol), value, data, ""); ActionInfo memory _actionInfo = ActionInfo( actionId, actionCreatorAaron, uint8(Roles.ActionCreator), mpStrategy1, address(mockProtocol), value, data ); vm.warp(block.timestamp + 1); _approveAction(approverAdam, _actionInfo); _approveAction(approverAlicia, _actionInfo); vm.warp(block.timestamp + 6 days); mpCore.queueAction(_actionInfo); vm.warp(block.timestamp + 5 days); vm.deal(actionCreatorAaron, value); vm.prank(actionCreatorAaron); (bool status, bytes memory _data) = address(mpCore).call{value: value}((abi.encodeCall(mpCore.executeAction, (_actionInfo)))); assertTrue(status); // Call revert here but it should not }
The execute
function should be made payable and the executeAction
should call execute
with {value: msg.value}
L334: executor.execute{value: msg.value}(actionInfo.target, actionInfo.value, action.isScript, actionInfo.data);
call/delegatecall
#0 - 0xSorryNotSorry
2023-06-18T14:09:05Z
The issue is well demonstrated, properly formatted, contains a coded POC. Marking as HQ.
#1 - c4-pre-sort
2023-06-18T14:09:09Z
0xSorryNotSorry marked the issue as high quality report
#2 - c4-pre-sort
2023-06-19T11:11:42Z
0xSorryNotSorry marked the issue as duplicate of #255
#3 - c4-pre-sort
2023-06-19T11:13:32Z
0xSorryNotSorry marked the issue as not a duplicate
#4 - c4-pre-sort
2023-06-19T11:16:34Z
0xSorryNotSorry marked the issue as duplicate of #247
#5 - c4-judge
2023-07-02T10:20:26Z
gzeon-c4 changed the severity to 2 (Med Risk)
#6 - c4-judge
2023-07-02T10:25:01Z
gzeon-c4 marked the issue as satisfactory