Platform: Code4rena
Start Date: 05/05/2022
Pot Size: $125,000 DAI
Total HM: 17
Participants: 62
Period: 14 days
Judge: leastwood
Total Solo HM: 15
Id: 120
League: ETH
Rank: 13/62
Findings: 2
Award: $1,347.64
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: tintin
Also found by: 0xsomeone, AuditsAreUS, hyh
1164.4755 DAI - $1,164.48
https://github.com/code-423n4/2022-05-alchemix/blob/de65c34c7b6e4e94662bf508e214dcbf327984f4/contracts-full/AlchemicTokenV2Base.sol#L111-L124 https://github.com/code-423n4/2022-05-alchemix/blob/de65c34c7b6e4e94662bf508e214dcbf327984f4/contracts-full/AlchemicTokenV2Base.sol#L189-L191
An alchemist / user can mint more than their alloted amount of AlTokens by calling lowerHasMinted()
before they reach their minting cap.
Function mint()
in AlchemicTokenV2Base.sol
function mint(address recipient, uint256 amount) external onlyWhitelisted { if (paused[msg.sender]) { revert IllegalState(); } uint256 total = amount + totalMinted[msg.sender]; if (total > mintCeiling[msg.sender]) { revert IllegalState(); } totalMinted[msg.sender] = total; _mint(recipient, amount); }
Note the require conditional check that total > mintCeiling[msg.sender]
.
In the same contract, there is the function lowerHasMinted()
with the same permission level as mint and is thus callable by the same user as well.
function lowerHasMinted(uint256 amount) external onlyWhitelisted { totalMinted[msg.sender] = totalMinted[msg.sender] - amount; }
It is clear that a user can accumulate an infinite (within supply) amount of AlTokens by calling lowerHasMinted()
before any action that would make them exceed their minting cap.
Manual review, VScode
Change the permissioning on lowerHasMinted()
to be restricted to a higher permissioned role like onlySentinel()
, or deprecate this function as I could not find any uses of it throughout the codebase or in tests.
#0 - 0xfoobar
2022-05-30T06:43:06Z
Sponsor confirmed
#1 - 0xleastwood
2022-06-02T19:08:55Z
Great find! This would allow whitelisted account to mint any number of tokens. However, as this pertains to only whitelisted accounts, I think medium
severity is justified and correct.
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xkatana, 0xsomeone, AuditsAreUS, BouSalman, BowTiedWardens, Cityscape, Funen, GimelSec, Hawkeye, JC, MaratCerby, MiloTruck, Picodes, Ruhum, TerrierLover, WatchPug, Waze, bobirichman, catchup, cccz, cryptphi, csanuragjain, delfin454000, ellahi, fatherOfBlocks, hake, horsefacts, hyh, jayjonah8, joestakey, kebabsec, kenta, mics, oyc_109, robee, samruna, shenwilly, sikorico, simon135, throttle, tintin
183.1627 DAI - $183.16
Relevant portions of code are marked with @audit
tag.
gALCX.sol:reApprove()
function reApprove() public { // @audit check success return value for approve bool success = alcx.approve(address(pools), type(uint256).max); }
Suggested: require(success, "failed to approve");
EthAssetManager.sol:sweepToken()
function sweepToken(address token, uint256 amount) external lock onlyAdmin { // @audit prevent withdraw of specific tokens like `curveToken` SafeERC20.safeTransfer(address(token), msg.sender, amount); emit SweepToken(token, amount); }
The functionality of sweepToken is used to send any amount of any ERC20 token held by the EthAssetManager to the admin. However, there is no restriction on which tokens can be sent. Thus, the admin, which can be an EOA address, can sweep all underlying curveTokens
to themselves, stealing the rewards generated in Convex from the rewardReceiver
(called by claimRewards()
).
Same issue is in ThreePoolAssetManager.sol
.
Recommended Mitigation Steps:
Do not allow sweeping of the curveToken
and/or any other critical tokens.
gALCX.sol:reApprove()
a line under to public functions section// @audit move to section below function reApprove() public { bool success = alcx.approve(address(pools), type(uint256).max); } // PUBLIC FUNCTIONS
TransmuterV2.sol:setCollateralSource()
function setCollateralSource(address _newCollateralSource) external { _onlyAdmin(); buffer = _newCollateralSource; // @audit QA - emit NewCollateralSource event here }
Events are often emitted for changes to state throughout the codebase,and a changing of the collateral source should warrant one too.