Resupply crvUSD-wstUSR Market Post Mortem

Summary

  • A sophisticated exploit against Resupply's crvUSD-wstUSR pair created $10M of reUSD bad debt.

  • The vulnerability was unique to that specific pair. No other pairs are affected, and all Resupply markets continue to operate as usual.

  • The protocol guardian has set the debt limit to 0 on the affected pair and paused insurance pool withdrawals, with a formal governance vote required to unpause.

  • The exploit flow involved inflation of the CurveLend collateral shares, but differed from a classical "inflation attack" as it was carefully designed to nullify a borrower solvency check.

  • The section of code containing the issue was within scope for multiple security audits and independent researchers who were hired to review the codebase. None reported the issue.

  • Users are encouraged to visit the Resupply governance forums for updates on next steps.

Background

  • Resupply accepts ERC-4626 vault shares (CurveLend / FraxLend) as CDP collateral.

  • Oracles price vault shares via convertToAssets(), treating crvUSD and frxUSD as 1:1 with reUSD.

  • Resupply makes use of an Insurance Pool (IP) designed to facilitate liquidations and backstop bad debt across all pairs.

Attack Timeline

  • 2025-06-26 00:18:47 UTC — crvUSD-wstUSR pair deployed with a $10M debt limit; underlying CurveLend vault held 0 deposits.

  • 2025-06-26 01:53:59 UTC — Attack contract deployed and exploit executed (~1 h 35 m later).

  • 2025-06-26 02:53:23 UTC - Protocol guardian pauses affected pair.

Exploit Flow

  • Because the Curvelend vault had no deposits, it made it possible for the attacker to dramatically manipulate the share price, making 1 wei of shares worth 2e18 crvUSD by:

    • donating 2,000e18 crvUSD to the vault's controller (which holds vault funds)

    • depositing 2e18 crvUSD to mint 1 wei of vault shares

  • While share price manipulation is a critical step in this attack, it alone is not a problem for the Resupply oracle, as the true value of the shares is tracked correctly.

  • Unlike a traditional "inflation attack", the attack relied on triggering the following edge case in the smart contract logic:

    1. The oracle uses a hardcoded 1e18 shares parameter to correctly price the shares:

      _price = IERC4626(_vault).convertToAssets(1e18); // returns 2e36
      
    2. The pair then calculates the reUSD exchangeRate using the following evm math, which rounds to 0.

      exchangeRate = 1e36 / oracle.getPrices(collateral); // 1e36 / 2e36 floors to 0
      
      
    3. While an exchange rate of 0 in the previous step may appear harmless, it is relied upon in the following solvency check during each borrow operation:

      function _isSolvent(address _borrower, uint256 _exchangeRate) internal view returns (bool) {
          ...
          uint256 _ltv = ((_borrowerAmount * _exchangeRate * LTV_PRECISION) / EXCHANGE_PRECISION) / _collateralAmount;
          return _ltv <= _maxLTV; // _ltv = 0 ➔ always solvent
      }
      
      

      The multiplication by 0 breaks solvency check by causing the user's LTV to resolve to 0, thus causing _isSolvent() to return true regardless of the attacker's actual loan to value ratio.

  • This sequence of logic allowed the attacker to borrow up to the pair's full 10M reUSD debt limit.

Actions

  • The protocol guardian has paused the affected pair, setting its borrow limit to 0.

  • The Resupply treasury has used treasury funds to repay 643,051 reUSD debt

  • A new interest rate calculator was added to the pair to set its interest rate to 0%, preventing interest from accumulating on the bad debt.

  • The withdrawal timer window has been set to zero, temporarily blocking insurance pool assets from exiting until a governance proposal is passed.

  • A permissionless share burner contract has been deployed, funded, and used to trustlessly ensure all Resupply pairs are safe from a similar attack.

Next Steps

  • A formal governance proposal will facilitate the disposition of insurance pool assets, and to unblock the funds.

  • Stolen funds remain on-chain. The situation is being monitored and necessary steps are being taken.

  • Patch ResupplyPairCore.sol and ResupplyPairDeployer.sol to permanently defend against this form of attack.

References