Platform: Code4rena
Start Date: 04/03/2024
Pot Size: $140,000 USDC
Total HM: 19
Participants: 69
Period: 21 days
Judge: 0xean
Total Solo HM: 4
Id: 343
League: ETH
Rank: 15/69
Findings: 1
Award: $1,503.18
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: lightoasis
Also found by: 0xleadwizard, Tendency, alexfilippov314, ladboy233, wangxx2026
1503.1753 USDC - $1,503.18
https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/team/TimelockTokenPool.sol#L168-L173 https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/team/TimelockTokenPool.sol#L208-L223 https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/team/TimelockTokenPool.sol#L176-L199
User airdropped tokens may be stolen
With the withdraw method, we can see that the signature of this withdrawal has no reuse prevention mechanism added to it https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/team/TimelockTokenPool.sol#L168-L173
function withdraw(address _to, bytes memory _sig) external { if (_to == address(0)) revert INVALID_PARAM(); bytes32 hash = keccak256(abi.encodePacked("Withdraw unlocked Taiko token to: ", _to)); address recipient = ECDSA.recover(hash, _sig); // @audit The signature can always be reused _withdraw(recipient, _to); }
With the _getAmountUnlocked method, we can see that the number of tokens that can be withdrawn is unlocked over time. https://github.com/code-423n4/2024-03-taiko/blob/f58384f44dbf4c6535264a472322322705133b11/packages/protocol/contracts/team/TimelockTokenPool.sol#L239-L243
function _getAmountUnlocked(Grant memory _grant) private view returns (uint128) { return _calcAmount( _getAmountOwned(_grant), _grant.unlockStart, _grant.unlockCliff, _grant.unlockPeriod ); // @audit Unlocked over time }
If the user grants another user the right to withdraw the now unlocked amount of tokens, after the user withdraws. As time goes by, more tokens will be unlocked, and the user who got the signature can continue to withdraw tokens, and there is no way to cancel the signature. Restrictions are grant.costPerToken or the user granting the TimelockTokenPool contract can get the number of costToken. If costPerToken is 0, or the number of approvals is max, the user acquiring the signature can acquire as many as they want. If there is a finite number of approvals, the user signing can also withdraw money early after seeing a new grant from the user
Manual Review
Add nonces to prevent the signature from being reused.
Access Control
#0 - c4-pre-sort
2024-03-28T18:50:39Z
minhquanym marked the issue as duplicate of #60
#1 - c4-judge
2024-04-10T11:21:12Z
0xean marked the issue as satisfactory
#2 - c4-judge
2024-04-10T11:21:26Z
0xean changed the severity to 3 (High Risk)