All incidents

Helio Plugin Donation Inflation

Share
Jun 17, 2023 17:01 UTCAttackLoss: 685,999.7 ANKR, 25,296.12 lisUSD +1 morePending manual check1 exploit txWindow: Atomic
Estimated Impact
685,999.7 ANKR, 25,296.12 lisUSD +1 more
Label
Attack
Exploit Tx
1
Addresses
4
Attack Window
Atomic
Jun 17, 2023 17:01 UTC → Jun 17, 2023 17:01 UTC

Exploit Transactions

TX 1BSC
0x4a304ff08851106691f626045b0f55d403e3a0958363bdf82b96e8ce7209c3a6
Jun 17, 2023 17:01 UTCExplorer

Victim Addresses

0x13ae975c5a1198e4f47c68c31c1230694dc44a57BSC
0xf8527dc5611b589cbb365acacaac0d1dc70b25cbBSC
0x10b6f851225c203ee74c369ce876beb56379fca3BSC
0xb2b01d6f953a28ba6c8f9e22986f5bddb7653aeaBSC

Loss Breakdown

685,999.7ANKR
25,296.12lisUSD
1,148.26ankrBNB

Similar Incidents

Root Cause Analysis

Helio Plugin Donation Inflation

1. Incident Overview TL;DR

At BSC block 29185769, transaction 0x4a304ff08851106691f626045b0f55d403e3a0958363bdf82b96e8ce7209c3a6 exploited Helio's plugin-backed fsAMM-HAY/BUSD market. The attacker reduced the market's cToken supply to dust, then deposited LP directly into the market's ERC4626 plugin vault with the market itself as the share receiver. That donation inflated the market exchange rate without minting matching fsAMM cTokens, so Helio's comptroller treated the dust collateral as highly valuable and allowed the attacker cluster to drain assets from fANKR, fHAY, and fankrBNB.

The root cause is a broken accounting invariant in the plugin market design: market cash increased through externally minted plugin shares even though cToken supply did not increase. That violated the requirement that each outstanding cToken represent a fair share of legitimately supplied underlying.

2. Key Background

Helio's fsAMM-HAY/BUSD market is not a plain ERC20-backed cToken. It is a plugin-backed market that deposits the underlying LP token into an ERC4626-style vault and treats the vault position as market cash.

The critical accounting path is in the victim market implementation:

Origin: Helio CErc20PluginDelegate victim code.

function getCashPrior() internal view override returns (uint256) {
  return plugin.previewRedeem(plugin.balanceOf(address(this)));
}

function doTransferIn(address from, uint256 amount) internal override returns (uint256) {
  require(EIP20Interface(underlying).transferFrom(from, address(this), amount), "send");
  deposit(amount);
  return amount;
}

function deposit(uint256 amount) internal {
  plugin.deposit(amount, address(this));
}

That logic is only safe if plugin shares credited to the market can only be created through the market's own mint flow. The paired vault interface does not enforce that:

Origin: Helio plugin vault ERC4626 interface.

function deposit(uint256 underlyingAmount, address to) external returns (uint256 shares);

Because deposit accepts an arbitrary to address, any caller can mint plugin shares directly to the fsAMM market address. Once that happens, getCashPrior() counts those donated shares as market backing even though no new fsAMM cTokens were minted.

3. Vulnerability Analysis & Root Cause Summary

This is an ATTACK-class accounting exploit in a plugin-backed collateral market. The exploitable invariant is that increases in collateral backing must be paired with proportional increases in cToken supply. Helio broke that invariant by valuing fsAMM cash as plugin.previewRedeem(plugin.balanceOf(market)) while the plugin vault allowed arbitrary third parties to mint shares to market. An attacker could therefore create a tiny outstanding cToken supply, donate a large amount of LP to the vault on behalf of the market, and make each remaining fsAMM cToken represent an artificially huge amount of underlying. Helio's comptroller used that inflated exchange rate in its collateral calculations and permitted borrowing against it. The exploit remained permissionless because every component used by the attacker was public: flash liquidity, public Helio markets, and unrestricted vault entry points. The incident therefore satisfies the ACT model.

4. Detailed Root Cause Analysis

The attacker cluster used public ANKR flash liquidity and public Helio markets only. First, the borrower account supplied 34,494,086.936027488122501834 raw ANKR to fANKR, establishing borrowable collateral. In parallel, the attacker contract minted a small fsAMM-HAY/BUSD position from LP and immediately redeemed almost all of it, leaving only 1001 fsAMM cTokens outstanding for the borrower cluster.

The decisive step was a direct vault deposit to the plugin on behalf of the market itself:

Origin: seed trace, direct plugin donation.

TransparentUpgradeableProxy::fallback(
  238641886110500562471821,
  CErc20Delegator: [0xF8527Dc5611B589CbB365aCACaac0d1DC70b25cB]
)
  0xC3F159eB41b75BF79bbC099AFB63ED0c74d6aEC5::deposit(
    238641886110500562471821,
    CErc20Delegator: [0xF8527Dc5611B589CbB365aCACaac0d1DC70b25cB]
  )
  emit Deposit(
    param0: 0xC40119C7269A5FA813d878BF83d14E3462fC8Fde,
    param1: CErc20Delegator: [0xF8527Dc5611B589CbB365aCACaac0d1DC70b25cB],
    param2: 238641886110500562471821,
    param3: 238641886110500562471821
  )

That call moved fresh LP into the vault and minted new plugin shares to the fsAMM market address, not to the attacker. Since the market's cash calculation looks only at plugin.balanceOf(address(this)), the donated shares became indistinguishable from legitimately market-minted backing. No new fsAMM cTokens were created during this step, so the market's exchange rate inflated sharply over a dust cToken supply.

The trace later shows the post-donation borrow and one-token redemption behavior:

Origin: seed trace, post-inflation borrow and redemption.

0x96954e4ab0fa5a10C5f2DB11B681D17E704574B7::borrow(
  685999702783572563751255
)

emit Redeem(
  : 0xC40119C7269A5FA813d878BF83d14E3462fC8Fde,
  : 519134100928882317409,
  : 1
)

This proves both sides of the invariant break. Helio accepted the inflated fsAMM collateral value and allowed borrowing of 685999702783572563751255 raw ANKR from fANKR. Separately, a holder of only 1 fsAMM cToken could redeem 519134100928882317409 raw LP underlying, demonstrating that the donated value had been converted into redeemable market backing.

The realized depletion predicate is explicit in the balance diff. After the exploit transaction, fANKR lost 685999702783572563751254 raw ANKR, fHAY lost 25296116863562095022654 raw lisUSD, and fankrBNB lost 1148264532617591819152 raw ankrBNB. Those deltas make the ACT success condition deterministic without relying on fee conversion estimates.

5. Adversary Flow Analysis

The adversary cluster consisted of sender EOA 0x4b92cc3452ef1e37528470495b86d3f976470734, main attacker contract 0xc40119c7269a5fa813d878bf83d14e3462fc8fde, and borrower helper 0xd2094b870d80cfb7dada4893ad0030d642ca9f72.

The on-chain flow was:

  1. The attacker contract sourced ANKR through public flash liquidity from Pancake V2 pair 0x8028ac1195b6469de22929c4f329f96b06d65f25 and Algebra pool 0xc8cbf9b12552c0b85fc368aa530cc31e00526e2f.
  2. The borrower account supplied ANKR to fANKR at 0x13ae975c5a1198e4f47c68c31c1230694dc44a57.
  3. The attacker minted fsAMM-HAY/BUSD from LP, redeemed almost all of it, and transferred the remaining 1001 cTokens into the borrower cluster.
  4. The attacker directly called the plugin vault at 0x02706a482fc9f6b20238157b56763391a45be60e with receiver 0xf8527dc5611b589cbb365acacaac0d1dc70b25cb, the fsAMM market.
  5. Helio's comptroller at 0x1851e32f34565cb95754310b031c5a2fc0a8a905 then valued the dust fsAMM position using the inflated exchange rate and allowed borrowing and redemption from the other Helio markets.
  6. The borrower account borrowed and redeemed protocol assets, the flash liquidity was repaid, and the attacker cluster retained profit plus a remaining ankrBNB gain.

This sequence was fully adversary-crafted inside one public transaction and required no privileged role, private key compromise, or private orderflow dependency.

6. Impact & Losses

The exploit drained three Helio markets:

  • fANKR (0x13ae975c5a1198e4f47c68c31c1230694dc44a57) lost 685999702783572563751254 raw ANKR.
  • fHAY (0x10b6f851225c203ee74c369ce876beb56379fca3) lost 25296116863562095022654 raw lisUSD.
  • fankrBNB (0xb2b01d6f953a28ba6c8f9e22986f5bddb7653aea) lost 1148264532617591819152 raw ankrBNB.

Origin: seed transaction balance diff.

{
  "holder": "0x13ae975c5a1198e4f47c68c31c1230694dc44a57",
  "token": "0xf307910a4c7bbc79691fd374889b36d8531b08e3",
  "delta": "-685999702783572563751254"
}
{
  "holder": "0x10b6f851225c203ee74c369ce876beb56379fca3",
  "token": "0x0782b6d8c4551b9760e74c0545a9bcd90bdc41e5",
  "delta": "-25296116863562095022654"
}
{
  "holder": "0xb2b01d6f953a28ba6c8f9e22986f5bddb7653aea",
  "token": "0x52f24a5e03aee338da5fd9df68d2b6fae1178827",
  "delta": "-1148264532617591819152"
}

The attacker contract itself finished with 590964388569997952122303 raw ANKR and 116000000000000000000 raw ankrBNB after flash repayment, but the decisive incident predicate is the protocol depletion above.

7. References

  • Seed transaction: 0x4a304ff08851106691f626045b0f55d403e3a0958363bdf82b96e8ce7209c3a6
  • BSC block: 29185769
  • Victim protocol: Helio / Midas plugin markets
  • Key victim contracts:
  • fANKR: 0x13ae975c5a1198e4f47c68c31c1230694dc44a57
  • fsAMM-HAY/BUSD: 0xf8527dc5611b589cbb365acacaac0d1dc70b25cb
  • Plugin vault: 0x02706a482fc9f6b20238157b56763391a45be60e
  • fHAY: 0x10b6f851225c203ee74c369ce876beb56379fca3
  • fankrBNB: 0xb2b01d6f953a28ba6c8f9e22986f5bddb7653aea
  • Evidence artifacts:
  • Seed trace: /workspace/session/artifacts/collector/seed/56/0x4a304ff08851106691f626045b0f55d403e3a0958363bdf82b96e8ce7209c3a6/trace.cast.log
  • Seed balance diff: /workspace/session/artifacts/collector/seed/56/0x4a304ff08851106691f626045b0f55d403e3a0958363bdf82b96e8ce7209c3a6/balance_diff.json
  • Victim accounting code: /workspace/session/artifacts/collector/seed/56/0x13a2eb858aa1ace895a2a89ac6afd48bd6b1f8d7/src/compound/CErc20PluginDelegate.sol
  • Plugin interface: /workspace/session/artifacts/collector/seed/56/0x13a2eb858aa1ace895a2a89ac6afd48bd6b1f8d7/src/compound/IERC4626.sol
  • Verified-source confirmation for fHAY: https://api.etherscan.io/v2/api?chainid=56&module=contract&action=getsourcecode&address=0x10b6f851225c203ee74c369ce876beb56379fca3