Platform: Code4rena
Start Date: 04/03/2024
Pot Size: $88,500 USDC
Total HM: 31
Participants: 105
Period: 11 days
Judge: ronnyx2017
Total Solo HM: 7
Id: 342
League: ETH
Rank: 35/105
Findings: 1
Award: $398.02
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xjuan
Also found by: CaeraDenoir, Tigerfrake, Timenov, novamanbg, santiellena
398.0218 USDC - $398.02
https://github.com/code-423n4/2024-03-revert-lend/blob/main/src%2Ftransformers%2FV3Utils.sol#L115
The V3Utils::execute()
function facilitates token swapping, liquidity management, fee collection
, and other operations related to liquidity provision.
The vulnerability arises from the missing check that ensures the caller
of the execute()
function is the owner
of the token associated with the tokenId
. This means that anyone can call the execute()
function and perform operations on behalf of any token holder without proper authorization.
function execute(uint256 tokenId, Instructions memory instructions) public returns (uint256 newTokenId) {
When execute()
is called in executeWithPermit() in the line return execute(tokenId, instructions);
it performs the execution on the given tokenId
with proper access control.
However, he execute()
function is marked as public
, which means it can be called directly by any external account or contract.
This opens up the possibility for any caller
to execute instructions
on any arbitrary tokenId
, bypassing the access control
check performed in the executeWithPermit()
function.
This could potentially lead to unauthorized execution of instructions
on tokens that the caller should not have access to, violating the intended access control mechanism of the contract.
Without this check:
attacker
could call this function and perform actions on liquidity positions
owned by other users, potentially manipulating their positions or stealing their assets.Manual review
Adding the ownership check ensures that only the rightful owner of the token can execute operations on their own liquidity positions.
Add this check to the execute()
function.
if (nonfungiblePositionManager.ownerOf(tokenId) != msg.sender) { revert Unauthorized(); }
OR
To address this issue, you should consider making the execute function internal or private if it's only intended to be called internally within the contract. By making it internal or private, you ensure that it can only be invoked by other functions within the contract and not directly by external callers.
Here's how you can modify the function declaration:
function execute(uint256 tokenId, Instructions memory instructions) internal returns (uint256 newTokenId) { // Function implementation remains unchanged }
Access Control
#0 - c4-pre-sort
2024-03-22T16:28:49Z
0xEVom marked the issue as duplicate of #141
#1 - c4-pre-sort
2024-03-22T16:28:51Z
0xEVom marked the issue as sufficient quality report
#2 - c4-judge
2024-04-01T09:59:21Z
jhsagd76 marked the issue as satisfactory
#3 - c4-judge
2024-04-01T15:42:48Z
jhsagd76 changed the severity to 3 (High Risk)