On June 26, 2025 a single integer division flaw cost Resupply $9.56M. The attacker exploited an ERC4626 “first donation” vulnerability in the cvcrvUSD vault’s ResupplyPair contract (0x6e90c). They stole $10M through in one flash loan transaction (0xffbbd).

How did this happen?

The ResupplyFi protocol contains a vulnerability in its handling of ERC4626 vault collateral that allows attackers to manipulate exchange rates and bypass loan-to-value (LTV) checks, resulting in unauthorized borrowing. This vulnerability was successfully exploited in a real-world attack, resulting in $9.56 million in losses just hours after the protocol’s deployment.

Vulnerability Details

1. Exchange rate calculation vulnerability

Location: ResupplyPairCore.sol:573

_exchangeRate = 1e36 / IOracle(_exchangeRateInfo.oracle).getPrices(address(collateral));
Issue: Integer division without rounding protection causes the exchange rate to round down to zero when the oracle price becomes extremely large.

2. ERC4626 donation attack vector

Location: ResupplyPairCore.sol:155-156
underlying = IERC20(IERC4626(_collateral).asset());
The protocol accepts ERC4626 vaults as collateral, which are vulnerable to donation attacks. In the real-world exploit, the attacker targeted the cvcrvUSD vault which was nearly empty at deployment:
– Attacker can donate assets directly to the vault
– This inflates the price per share dramatically
– Oracle reports the inflated price accurately
– Exchange rate calculation breaks: `1e36 / extremely_large_number = 0`

3. Broken solvency check

Location: ResupplyPairCore.sol:282
uint256 _ltv = ((_borrowerAmount * _exchangeRate * LTV_PRECISION) / EXCHANGE_PRECISION) / _collateralAmount;
return _ltv <= _maxLTV;
When _exchangeRate = 0

– LTV calculation:

(_borrowerAmount * 0 * LTV_PRECISION) / EXCHANGE_PRECISION / _collateralAmount = 0

– Check: 0 <= _maxLTV always returns true

Result: Any amount of collateral allows unlimited borrowing

Attack scenario

Target: cvcrvUSD ERC4626 vault (nearly empty at deployment)
1. Initial manipulation:
The attacker deposited 1 wei into the empty cvcrvUSD vault, and then made a large donation to artificially inflate `pricePerShare`.
2. Exchange rate corruption:
The attacker:
– Called borrow() on newly deployed ResupplyPair
– Triggered oracle price fetch: getPrices(address(collateral))
– Price extremely high due to donation inflation
_exchangeRate = 1e36 / price computed to zero via Solidity floor division
3. Solvency bypass:
_isSolvent() check used corrupted _exchangeRate = 0

– LTV calculation:

(_borrowAmount * 0 * LTV_PRECISION) / EXCHANGE_PRECISION / _collateralAmount = 0

– Check 0 <= _maxLTV always returns true

4. Mass borrowing:
The attacker borrowed $10 million worth of reUSD using just 1 wei of collateral, and swapped and redistributed the stolen funds. This led to a final profit of $9.56 million split across multiple addresses.

Generic attack pattern

1. Target newly deployed or low-liquidity ERC4626 vault
2. Donate large amount of underlying assets to inflate share price
3. Mint minimal vault shares (1 wei)
4. Oracle price inflates to astronomical levels
5. Exchange rate rounds to zero due to integer division
6. Deposit minimal collateral and bypass LTV checks
7. Borrow maximum available funds

Recommendations

 Immediate mitigations

1. Add an exchange rate floor
_exchangeRate = 1e36 / IOracle(_exchangeRateInfo.oracle).getPrices(address(collateral));
require(_exchangeRate > 0, "Invalid exchange rate");
_exchangeRate = _exchangeRate == 0 ? 1 : _exchangeRate;

2. Add minimum collateral requirements

Enforce minimum deposit amounts for ERC4626 vaults and implement share/asset ratio sanity checks.

References

– ERC4626 Standard: https://eips.ethereum.org/EIPS/eip-4626
– ResupplyFi Official Response: https://x.com/ResupplyFi/status/1938092252431036491
– Target Vault: cvcrvUSD ERC4626 vault

Want to learn more? Read our recent blog covering the 2025 GMX hack.