Vulnerability Details
The addUnripeToken
function is used to add unripe token. But it can also be use to update the token details including the underlyingToken
. The problem is that the original function switchUnderlyingToken
that switch underlyingToken
ensures that the balance of the underlyingToken
is zero before updating it.
function switchUnderlyingToken(
address unripeToken,
address newUnderlyingToken
) external payable {
LibDiamond.enforceIsContractOwner();
@-> require(s.u[unripeToken].balanceOfUnderlying == 0, "Unripe: Underlying balance > 0");
LibUnripe.switchUnderlyingToken(unripeToken, newUnderlyingToken);
}
The addUnripeToken
function bypasses this, because this function has the ability to add and update the unripeToken
details including underlyingToken
, without any checks.
function addUnripeToken(
address unripeToken,
address underlyingToken,
bytes32 root
) external payable nonReentrant {
LibDiamond.enforceIsOwnerOrContract();
@-> s.u[unripeToken].underlyingToken = underlyingToken;
s.u[unripeToken].merkleRoot = root;
emit AddUnripeToken(unripeToken, underlyingToken, root);
}
Impact
Potential Loss of Funds
Tools Used
Manual Analysis
Recommendations
Add checks to ensures that the underlyingToken
for an unripeToken
is empty before updating it.
function addUnripeToken(
address unripeToken,
address underlyingToken,
bytes32 root
) external payable nonReentrant {
LibDiamond.enforceIsOwnerOrContract();
+ require(s.u[unripeToken].underlyingToken != address(0), "Unripe Token already exist");
s.u[unripeToken].underlyingToken = underlyingToken;
s.u[unripeToken].merkleRoot = root;
emit AddUnripeToken(unripeToken, underlyingToken, root);
}