#36931 [SC-Critical] critical creators can modifyloccollateral of dynamic loc to release ....
#36931 [SC-Critical] Creators can modifyLOCCollateral of dynamic LOC to release almost all the collateral of LOC
Submitted on Nov 20th 2024 at 05:08:07 UTC by @perseverance for Audit Comp | Anvil: Letters of Credit
Report ID: #36931
Report Type: Smart Contract
Report severity: Critical
Target: https://github.com/AcronymFoundation/anvil-contracts/blob/main/contracts/LetterOfCredit.sol
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Protocol insolvency
Description
Description
Brief/Intro
A Letter of Credit (LOC) is a contractual agreement that guarantees payment on time and in full from a buyer (creator) to a seller (beneficiary). The Anvil LOC comprises two elements: the collateral asset, which secures the LOC, and the credited asset, representing its redeemable value. The protocol supports LOC issuance irrespective of the collateral and credit asset types.
The critical aspect of every LOC is the redeemability of its full credited value. To mitigate potential market volatility all LOCs require sufficient overcollateralization. Liquidity must be available for collateral-asset-to-credited-asset conversion, guaranteeing beneficiaries invariably receive the credited asset.
It is important that all LOCs require sufficient overcollateralization.
The beneficiary or seller can based on the creditTokenAmount to sell the buyer something based on this LOC. The Credited amount is guaranteed to be backed by collateral that is worth more than the credited amount. The buy and sell activity is managed outside of the LetterOfCredit contract.
Users can create the Dynamic LOC by using function createDynamicLOC.
For example for the pair WETH and USDC, this creationCollateralFactorBasisPoints can be 6500 that is 65% so that the credited amount should be less than 65% of the collateral. This is to ensure that the all LOCs require sufficient overcollateralization.
Also the creators of the LOC can modify the collateral by calling modifyLOCCollateral to add or releaserelease the collateral, but still need to have the sufficient overcollateralization.
The vulnerability
Vulnerability Details
The vulnerability here is in the function modifyLOCCollateral does not check if the cfBasisPoints is 0
```solidity function modifyLOCCollateral( uint96 _locId, int256 _byAmount, bytes calldata _oraclePriceUpdate, bytes calldata _collateralizableAllowanceSignature ) external payable refundExcess nonReentrant { LOC memory loc = locs[_locId];
```
Here if the newCollateralAmount is very small, then cfBasisPoints might be 0 because the collateralInCredited is 0
```solidity function collateralFactorInBasisPoints( uint256 _collateralTokenAmount, uint256 _creditedTokenAmount, OraclePrice memory _price ) internal pure returns (uint16) { uint256 collateralInCredited = collateralAmountInCreditedToken(_collateralTokenAmount, _price); // Don't divide by 0 if (collateralInCredited == 0) { return 0; } return uint16((_creditedTokenAmount * 10_000) / collateralInCredited); } ```
So the creators can modifyCollateral to withdraw almost all the collateral. By exploiting this bug, the attacker breaks the stability of the system. The system is severely under collateralized and this can make the Protocol Insolvency scenario.
The attacker can modify the LOC and back the Credited Amount with with very small amount of collateral. This will result in victim loss of funds.
By exploiting this bug, the attacker can also create a lot of dynamic LOC with small collateral and can make creditedTokens[_creditedTokenAddress].globalAmountInDynamicUse equal or nearly equal to creditedToken.globalMaxInDynamicUse so other users of the protocol will not be able to create the dynamic LOC. Because users's call to function will failed in createDynamicLOC because of this check
```solidity function _validateAndUpdateCreditedTokenUsageForDynamicLOCCreation( address _creditedTokenAddress, uint256 _creditedTokenAmount ) private { CreditedToken memory creditedToken = creditedTokens[_creditedTokenAddress]; // ... uint256 newCreditedAmountInUse = creditedToken.globalAmountInDynamicUse + _creditedTokenAmount; if (newCreditedAmountInUse > creditedToken.globalMaxInDynamicUse) revert GlobalCreditedTokenMaxInUseExceeded(creditedToken.globalMaxInDynamicUse, newCreditedAmountInUse);
```
Impacts
About the severity assessment
Bug Severity: Critical
Impact category:
Protocol insolvency
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Difficulty of the attack: Easy
It is easy to automate the attack
Link to Proof of Concept
https://gist.github.com/Perseverancesuccess2021/831d502296049011991a7af9afe31abc#file-testletterofcredit-sol
Proof of Concept
Proof of concept
Steps to execute the attack:
Step 1: Attacker create a dynamicLOC for the victim with over-collaterized amount of collateral
Step 2: Attacker call modifyLOCCollateral to release almost all the collateral
Test code to show: https://gist.github.com/Perseverancesuccess2021/831d502296049011991a7af9afe31abc#file-testletterofcredit-sol
```solidity function testModifyLOCCollateral() public { setup_precondition();