Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

A malicious user can collect all the fees for themselves due to weak access control

Allowing msg.sedner to be onlyCollector leads to the msg.sender being able to collect all the fees for themselves.

Description

  • In the constructor the _collector parameter can be set to any address, as long as its not a zero address. Then it gets set equal to s_collector, which then gets checked in the modifier onlyCollector to see if the address is the msg.sender. If not then it reverts.

  • Now that the msg.sender is the onlyCollector they are able to call the function collectFee which will send all the weth from the contract to their address.

...
// >>> MODIFIERS
modifier onlyCollector() {
@> if (msg.sender != s_collector) {
revert S__NotAllowed();
}
_;
}
...
// >>> CONSTRUCTOR
@> constructor(address _weth, uint256 _buyFee, address _collector) ERC20("Snow", "S") Ownable(msg.sender) {
if (_weth == address(0)) {
revert S__ZeroAddress();
}
if (_buyFee == 0) {
revert S__ZeroValue();
}
if (_collector == address(0)) {
revert S__ZeroAddress();
}
i_weth = IERC20(_weth);
s_buyFee = _buyFee * PRECISION;
@> s_collector = _collector;
i_farmingOver = block.timestamp + FARMING_DURATION; // Snow farming eands 12 weeks after deployment
}
...
function collectFee() external onlyCollector {
uint256 collection = i_weth.balanceOf(address(this));
@> i_weth.transfer(s_collector, collection);
(bool collected,) = payable(s_collector).call{value: address(this).balance}("");
require(collected, "Fee collection failed!!!");
}

Risk

Likelihood: High

  • this could happen anytime time since the constructor needs an address for the _collector parameter, which then gets equaled to s_collector, which then is used as a check in the modifier onlycollector to see if s_collector is the msg.sender and if it's not it will revert. But we can't have that modifier revert because without it we can't call essential functions in the contract like collectFee and changeCollector.

Impact: High

  • This would lead to anyone being able to call the collectFee function and taking all the fees for themselves.

Proof of Concept

-Bob inputs his own address in the constructor parameters for _collector
-This parameter is then set equal to s_collector
-s_collector is then checked in the modifier onlyCollector to see if it's the address of msg.sender
-Now Bob gained access to the collectFee function since he's the onlyCollector
-Now Bob calls the function and transfers whatever fees have been accumulated to his address.

Recommended Mitigation

Instead of having the modifier revert if the s_collector isn't the msg.sender it should instead revert if it is the msg.sender.

- if (msg.sender != s_collector)
+ if (msg.sender = s_collector)
Updates

Lead Judging Commences

yeahchibyke Lead Judge 18 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.