Platform: Code4rena
Start Date: 24/10/2023
Pot Size: $36,500 USDC
Total HM: 4
Participants: 147
Period: 6 days
Judge: 0xDjango
Id: 299
League: ETH
Rank: 51/147
Findings: 1
Award: $119.14
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: josephdara
Also found by: 0xAadi, 0xmystery, 0xpiken, Arz, Beosin, Eeyore, HChang26, J4X, KIntern_NA, Limbooo, RamenPeople, SpicyMeatball, Team_Rocket, Yanchuan, castle_chain, degensec, ge6a, lanrebayode77, mert_eren, sorrynotsorry, tnquanghuy0512
119.1406 USDC - $119.14
https://github.com/code-423n4/2023-10-ethena/blob/main/contracts/StakedUSDe.sol#L232-L234
FULL_RESTRICTED_STAKER_ROLE
is still able to withdraw StakedUSDe tokens by approving to another address. It results in protocol has a risk of being unable to manipulate the funds of blacklisted address (by redistributeLockedAmount
function).
First, protocol intends to prevent the FULL_RESTRICTED_STAKER_ROLE
address from being able to withdraw StakedUSDe tokens:
function _withdraw(address caller, address receiver, address _owner, uint256 assets, uint256 shares) internal override nonReentrant notZero(assets) notZero(shares) { if (hasRole(FULL_RESTRICTED_STAKER_ROLE, caller) || hasRole(FULL_RESTRICTED_STAKER_ROLE, receiver)) { revert OperationNotAllowed(); } super._withdraw(caller, receiver, _owner, assets, shares); _checkMinShares(); }
However, this function doesn't check the role of the _owner
address. StakedUSDe
inherits the ERC4626 contract, which allows users to withdraw on behalf of another address by using their allowance.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC4626.sol#L260-L269
/** * @dev Withdraw/redeem common workflow. */ function _withdraw( address caller, address receiver, address owner, uint256 assets, uint256 shares ) internal virtual { if (caller != owner) { _spendAllowance(owner, caller, shares); } ...
Therefore, the FULL_RESTRICTED_STAKER_ROLE
can approve another address and use that address to withdraw StakedUSDe. This action leads the protocol to be at risk of being unable to manipulate the funds of blacklisted addresses.
For example, Alice is an attacker who deposited malicious/attacked funds, so the protocol blacklists her address. Subsequently, Ethena's admin wants to redistribute Alice's StakedUSDe tokens. However, Alice promptly approves a new address and uses that new address to withdraw StakedUSDe before the admin's transaction. Hence, Alice can escape with her funds, causing harm to the protocol.
Manual Review
Should add the check for the role of _owner
address in _withdraw
function:
if (hasRole(FULL_RESTRICTED_STAKER_ROLE, caller) || hasRole(FULL_RESTRICTED_STAKER_ROLE, receiver) || hasRole(FULL_RESTRICTED_STAKER_ROLE, _owner)) { revert OperationNotAllowed(); }
Access Control
#0 - c4-pre-sort
2023-10-31T19:01:05Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2023-10-31T19:01:12Z
raymondfam marked the issue as duplicate of #7
#2 - c4-pre-sort
2023-11-01T19:45:35Z
raymondfam marked the issue as duplicate of #666
#3 - c4-judge
2023-11-13T19:35:03Z
fatherGoose1 marked the issue as satisfactory