Summary
Executions managed through the executeUserOp()
function lack a mechanism to specify the ETH value sent in the call.
Vulnerability Details
The executeUserOp()
function is one of the supported methods to trigger executions in the Nexus smart account.
158: function executeUserOp(PackedUserOperation calldata userOp, bytes32) external payable virtual onlyEntryPoint {
159:
160: bytes calldata innerCall = userOp.callData[4:];
161: bytes memory innerCallRet = "";
162:
163:
164: if (innerCall.length > 0) {
165:
166: (address target, bytes memory data) = abi.decode(innerCall, (address, bytes));
167: bool success;
168:
169: (success, innerCallRet) = target.call(data);
170:
171: require(success, InnerCallFailed());
172: }
173:
174:
175: emit Executed(userOp, innerCallRet);
176: }
As we can see in the code snippet, the implementation decodes the target address and the calldata from the received data. However, it provides no mechanism to specify the ETH value attached to the call.
Impact
ETH value cannot be specified for calls executed through the executeUserOp()
function.
Tools Used
None.
Recommendations
Add support for a third argument that indicates the value to use in the call.
if (innerCall.length > 0) {
// Decode target address and call data from inner call.
- (address target, bytes memory data) = abi.decode(innerCall, (address, bytes));
+ (address target, uint256 value, bytes memory data) = abi.decode(innerCall, (address, uint256, bytes));
bool success;
// Perform the call to the target contract with the decoded data.
- (success, innerCallRet) = target.call(data);
+ (success, innerCallRet) = target.call{value: value}(data);
// Ensure the call was successful.
require(success, InnerCallFailed());
}