Closed code423n4 closed 1 year ago
minhquanym marked the issue as primary issue
minhquanym marked the issue as high quality report
skimaharvey marked the issue as sponsor disputed
If you want to achieve this you can just use 0xffffffff
as selector and 00000001
(transfer value) as calltype.
This will only let you make a transfer to the receive()
or fallback()
(if there is not receive function) functions of the receiver.
The problem here is that you are using 0x00000000
as selector
trust1995 marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2023-06-lukso/blob/main/contracts/LSP6KeyManager/LSP6Modules/LSP6ExecuteModule.sol#L399-L416
Vulnerability details
Bug Description
Whenever a controller attempts to call a LSP0 account's
execute()
function without the relevant SUPER permissions,LSP6ExecuteModule
will check that the call is one of the whitelisted allowed calls.If the controller is trying to perform a call with no calldata (eg.
.call("")
),_extractExecuteParameters()
decodes its function selector to0x00000000
:LSP6ExecuteModule.sol#L352-L355
However, the
_isAllowedFunction()
will always returnfalse
for a0x00000000
function selector if the allowed call only allows a specific function to be called:LSP6ExecuteModule.sol#L410-L415
As
_isAllowedFunction()
is used to verify if the call being executed is whitelisted in allowed calls, this means thatexecute()
calls with empty calldata will always fail.This is an issue as:
TRANSFERVALUE
permission but don't haveCALL
permission are only allowed to callexecute()
with empty calldata.allowedFunction
of an allowed call to0xffffffff
will allow users with both permissions to call other functions in the contract at the same address.For instance, if a user wants to allow other users to send LYX to a contract with a
receive()
function (eg. other LSP0 accounts), but doesn't want them to be able to call other functions in the same contract, he will be unable to do so.Impact
Due to how calls with empty calldata are handled in
LSP6ExecuteModule
,LSP6KeyManager
cannot be configured to only allow only transfers of LYX to a contract with areceive()
function for users withoutSUPER_TRANSFERVALUE
permission.Proof of Concept
The following Foundry test demonstrates how calling
execute()
with empty calldata to transfer LYX will revert with theNotAllowedCall()
error:Recommended Mitigation
In
_isAllowedFunction()
, consider allowing the0x00000000
function selector if the call has empty calldata andallowedFunction
is set tobytes(0)
:LSP6ExecuteModule.sol#L399-L416
Assessed type
Invalid Validation