Platform: Code4rena
Start Date: 27/10/2022
Pot Size: $33,500 USDC
Total HM: 8
Participants: 96
Period: 3 days
Judge: kirk-baird
Total Solo HM: 1
Id: 176
League: ETH
Rank: 54/96
Findings: 2
Award: $29.55
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: ladboy233
Also found by: 0x52, 0xDecorativePineapple, 0xhunter, Aymen0909, Bnke0x0, Dravee, JTJabba, Jeiwan, Lambda, Nyx, Picodes, Trust, cccz, cryptonue, csanuragjain, dic0de, hansfriese, horsefacts, imare, minhtrng, pashov, peritoflores, rbserver, rvierdiiev, wagmi, yixxas
9.9073 USDC - $9.91
https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L653-L661 https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L585-L592
Hacked or malicious admin can transfer all tokens of WardenPledge
to himself.
WardenPledge.recoverERC20
function allows to transfer tokens controlled by contract if the token is not whitelisted.
function recoverERC20(address token) external onlyOwner returns(bool) { if(minAmountRewardToken[token] != 0) revert Errors.CannotRecoverToken(); uint256 amount = IERC20(token).balanceOf(address(this)); if(amount == 0) revert Errors.NullValue(); IERC20(token).safeTransfer(owner(), amount); return true; }
The check if(minAmountRewardToken[token] != 0) revert Errors.CannotRecoverToken();
is done to not allow admin to send tokens that are used for sending rewards to himself.
But there is another function that allows admin to remove token from whitelisted.
function removeRewardToken(address token) external onlyOwner { if(token == address(0)) revert Errors.ZeroAddress(); if(minAmountRewardToken[token] == 0) revert Errors.NotAllowedToken(); minAmountRewardToken[token] = 0; emit RemoveRewardToken(token); }
Using this function admin can first remove token from whitelisted and then recover tokens to himself.
I believe this is important thing and protocol should secure this. Because even if admin is not malicious, but ownership somehow was hacked, this gives ability for the attacker to get all funds and pausing can't help here.
VsCode
You can disallow to blocklist token if the WardenPledge
balance is not 0.
#0 - Kogaroshi
2022-10-30T22:39:51Z
PoC of the Issue is correct, but Remediation brings another issue in the system: in the case of a malicious or bugged token that was whitelisted, and currently in use for a Pledge, that needs to be removed from the whitelist, this would be impossible because the contract balance won't be 0.
Will look for an in-between that could prevent the scenario doing most of the damages to the system.
#1 - Kogaroshi
2022-11-01T13:58:42Z
Fixed in PR 2, commit Decided on a different way to fix this:
recoverERC20()
method to ignore the whitelist, but forbidding the method to touch any token belonging to Pledges.That way, admin has no way to touch any Pledge rewards or rug any funds, even after removing a token from the whitelist. The new system also allows to retrieve the reward token sent directly to the contract by mistake, without touching any Pledge rewards.
#2 - c4-judge
2022-11-09T21:29:02Z
kirk-baird marked the issue as satisfactory
#3 - c4-judge
2022-11-09T21:51:05Z
kirk-baird marked the issue as primary issue
#4 - c4-judge
2022-12-06T17:32:42Z
Simon-Busch marked the issue as duplicate of #68
🌟 Selected for report: robee
Also found by: 0x007, 0x1f8b, 0x52, 0xDjango, 0xNazgul, 0xSmartContract, 8olidity, Awesome, B2, Bnke0x0, Chom, Diana, Dravee, JTJabba, Jeiwan, Josiah, Lambda, Mathieu, Picodes, RaoulSchaffranek, RaymondFam, RedOneN, ReyAdmirado, Rolezn, Ruhum, Sm4rty, Tricko, Trust, Waze, __141345__, a12jmx, adriro, ajtra, brgltd, c3phas, carlitox477, cccz, ch0bu, chaduke, chrisdior4, corerouter, cryptonue, csanuragjain, ctf_sec, cylzxje, delfin454000, dic0de, djxploit, horsefacts, imare, jayphbee, jwood, ktg, ladboy233, leosathya, lukris02, minhtrng, neko_nyaa, oyc_109, pashov, peritoflores, rbserver, rvierdiiev, shark, tnevler, yixxas
19.6449 USDC - $19.64
No need to calculate how much is 1 week in seconds. You can use solidity 1 weeks
variable instead. uint256 public constant WEEK = 1 weeks;
https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L24
Use constant instead of magic number 500
inside updatePlatformFee
function.
https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L626
WardenPledge
can be initialized with 0 chest
address which leads to unpredictable behaviour of protocol.In constructor of WardenPledge
there is no check that chest address is not 0. However it is in setter.
chest
address is used in different places of code to transfer protocol fees to it using IERC20(rewardToken).safeTransferFrom(creator, chestAddress, vars.feeAmount);
.
If chest
value was initialized as 0 using constructor then the behaviour of protocol will depend on reward token.
Different reward tokens will give different results. Some will revert, because of sending to 0 address, while someone will still work.
As the result, in one option protocol will be working with reward token, but will burn protocol fees and in another option, protocol will revert when sending fees.
Make sure that chest != address(0)
in constructor.
#0 - c4-judge
2022-11-09T06:48:36Z
kirk-baird marked the issue as grade-b