Description:Description\
An USDE blacklisted user can bypass USDE blacklisting mechanism calling InvestToken::deposit setting as receiver a whitelisted address.
Severity: High cause a blacklisted user with a USDE positive balance can bypass blacklist leading USDE blacklisting mechanism useless.
Attack Scenario\
If an address A on validator is blacklisted ie
Validator::accountStatus[A] = Status.BLACKLISTED;
Then A cant mint and transfer tokens to it, cause USDE::_update function is overriden to:
function _update(address from, address to, uint256 amount) internal override(ERC20*) {
require(validator.isValid(from, to), "account blocked");
//...
}
However a blacklisted user (A) with USDE positive balance (A_BALANCE), can bypass USDE blacklist by calling InvestToken::deposit(A_BALANCE, R) with a whitelisted address (R) as a receiver.
Because R is whitelisted and from == address(0) it will return true.
So InvestToken::deposit [1] returns true, and [2] returns true.
Also, observe InvestToken::deposit doesnt have any access control modifier so it can be called by anyone at anytime, so even if a user is blacklisted it can move USDE by calling InvestToken::deposit
Github username: -- Twitter username: -- Submission hash (on-chain): 0xf0079c5ee732b3c06e6114d1c85d449d2e7a2b6bdb166573431b48978a1b7fe8 Severity: high
Description: Description\ An USDE blacklisted user can bypass USDE blacklisting mechanism calling InvestToken::deposit setting as receiver a whitelisted address.
Severity: High cause a blacklisted user with a USDE positive balance can bypass blacklist leading USDE blacklisting mechanism useless.
Attack Scenario\ If an address A on validator is blacklisted ie
Then A cant mint and transfer tokens to it, cause USDE::_update function is overriden to:
However a blacklisted user (A) with USDE positive balance (A_BALANCE), can bypass USDE blacklist by calling InvestToken::deposit(A_BALANCE, R) with a whitelisted address (R) as a receiver.
This will work because in:
[1] InvestToken::deposit(A_BALANCE, R) call flow will be ->
Where USDE::_update is defined as:
ie USDE::_update will call validator.isValid(A, 0x0):
Because A is blacklisted it checks if to == address(0), because it is, (its a burn call) then validator::isValid will return true.
So, in [2] InvestToken::deposit(A_BALANCE, R) flow call will be
where InvestToken::_update is defined as:
So it will call validator.isValidStrict(address(0), R), where validator::isValidStrict is defined as:
Because R is whitelisted and from == address(0) it will return true.
So InvestToken::deposit [1] returns true, and [2] returns true. Also, observe InvestToken::deposit doesnt have any access control modifier so it can be called by anyone at anytime, so even if a user is blacklisted it can move USDE by calling InvestToken::deposit
Attachments
Proof of Concept (PoC) File
Revised Code File (Optional)