All incidents

EAC Treasury Buy Was Public

Share
Aug 29, 2023 10:08 UTCAttackLoss: 14,300 USDTPending manual check1 exploit txWindow: Atomic
Estimated Impact
14,300 USDT
Label
Attack
Exploit Tx
1
Addresses
2
Attack Window
Atomic
Aug 29, 2023 10:08 UTC → Aug 29, 2023 10:08 UTC

Exploit Transactions

TX 1BSC
0x477f9ee698ac8ae800ffa012ab52fd8de39b58996245c5e39a4233c1ae5f1baa
Aug 29, 2023 10:08 UTCExplorer

Victim Addresses

0xa08a40e0f11090dcb09967973df82040bff63561BSC
0x64f291de10ecd36d5f7b64aaebc70943cface28eBSC

Loss Breakdown

14,300USDT

Similar Incidents

Root Cause Analysis

EAC Treasury Buy Was Public

1. Incident Overview TL;DR

On BNB Chain block 31273019, attacker EOA 0x27e981348c2d1f5b2227c182a9d0ed46eed84946 sent transaction 0x477f9ee698ac8ae800ffa012ab52fd8de39b58996245c5e39a4233c1ae5f1baa to helper contract 0x20dcf125f0563417d257b98a116c3fea4f0b2db2. The helper borrowed USDT from DODO pool 0x26d0c625e5f5d6de034495fbde1f6e9377185618, bought EAC, forced the PyramidRelation treasury proxy 0xa08a40e0f11090dcb09967973df82040bff63561 to spend its own USDT buying more EAC, then sold back into the inflated market, repaid the flashloan, and retained the residual value as WBNB.

The root cause is an unprotected treasury-spending implementation function behind the PyramidRelation proxy. Selector 0xe6a24c3f allowed any caller to spend the proxy's USDT through PancakeSwap with a caller-chosen amount, so the attacker could trigger treasury buying exactly when it maximized the value of the attacker's own EAC position.

2. Key Background

The exploited market structure combines three permissionless components:

  • DODO pool 0x26d0c625e5f5d6de034495fbde1f6e9377185618, which provided public flash liquidity in USDT.
  • PyramidRelation proxy 0xa08a40e0f11090dcb09967973df82040bff63561, which held a treasury USDT balance.
  • EAC token 0x64f291de10ecd36d5f7b64aaebc70943cface28e, whose transfer logic triggers PlanA() and causes additional EAC and STEAC market movement on buys and sells.

The verified EAC source shows that buy and sell transfers route fees to fundReward and immediately call EACFund(fundReward).PlanA(). The verified STEAC-side source shows that PlanA() ultimately sells accumulated token inventory through PancakeSwap. That means a large treasury buy in EAC does more than move the USDT/EAC pair directly: it also triggers additional tokenomic side effects that further disturb reserves and pricing.

The new implementation evidence artifact for PyramidRelation establishes that selector 0xe6a24c3f is the critical victim-side entrypoint. It dispatches to a code path that reads the proxy's USDT balance, enforces only amount <= balance, approves the Pancake router, and calls swapExactTokensForTokensSupportingFeeOnTransferTokens with hardcoded recipient 0x279b8306bb7cd010eedf1227536464a31d6afea1. A separate selector 0xcec26e51 performs an owner check, which makes the lack of a caller check on 0xe6a24c3f explicit rather than inferred.

3. Vulnerability Analysis & Root Cause Summary

The vulnerability is a direct access-control failure on a treasury-trading path. PyramidRelation exposed a function that spends treasury USDT and buys EAC, but the function did not validate that the caller was the owner or an approved manager. As a result, any unprivileged contract could time a treasury buy around its own market position. That transformed the treasury into a public price-support primitive.

The broken invariant is straightforward: only authorized protocol operators should be able to deploy treasury USDT into market trades. The code-level breakpoint is selector 0xe6a24c3f in implementation 0xb803ed66ab449d80ed12cacf83eae5147fdc6922, which executes approve(ROUTER, amount) followed by swapExactTokensForTokensSupportingFeeOnTransferTokens(amount, 0, [USDT, EAC], 0x279b..., block.timestamp) after checking only that the requested amount does not exceed the proxy's USDT balance.

This is an ACT case rather than a privileged compromise. The attacker used only public liquidity, a locally deployed helper contract, and publicly callable on-chain functions. No private keys, privileged roles, or attacker-specific artifacts were required.

4. Detailed Root Cause Analysis

The implementation evidence collected for the victim contract is the decisive proof. The artifact records the following observations for implementation 0xb803ed66ab449d80ed12cacf83eae5147fdc6922:

- 0x0063-0x0069 dispatch selector 0xe6a24c3f to function body 0x0114 / 0x037f.
- 0x02e3-0x0354 handles selector 0xcec26e51 and checks CALLER against owner before mutating storage.
- 0x037f-0x057b handles selector 0xe6a24c3f and contains no CALLER comparison.
- 0x0408-0x046f issues staticcall 0x70a08231 (balanceOf) against token slot 0x02 with address(this).
- 0x0472-0x047e enforces only amount <= balance by LT / ISZERO before continuing.
- 0x047f-0x04f8 issues approve(address,uint256) with selector 0x095ea7b3 to the USDT token.
- 0x04f9-0x0562 issues router call selector 0x5c11d795.

That code path matches the on-chain exploit trace. The seed trace shows the attacker helper calling the proxy, the proxy delegating into the implementation, and the implementation spending the treasury's USDT:

Trace line 19203: attacker helper 0x20dc... -> proxy 0xa08a...
Trace line 19337: proxy delegatecalls implementation 0xb803...
Trace lines after the delegatecall: USDT balance check, USDT approve, Pancake router swap

The balance diff independently confirms the state transition produced by that call:

{
  "token": "0x55d398326f99059ff775485246999027b3197955",
  "holder": "0xa08a40e0f11090dcb09967973df82040bff63561",
  "before": "14300000000000000000000",
  "after": "0",
  "delta": "-14300000000000000000000"
}

The rest of the exploit is economically straightforward once the treasury-buy primitive is public:

  1. The attacker flash-borrows 300000.000000000008388608 USDT from the DODO pool.
  2. The attacker buys EAC with that flash liquidity, establishing a large position before the forced treasury trade.
  3. The attacker calls selector 0xe6a24c3f on PyramidRelation, causing the treasury to spend all 14300 USDT buying EAC.
  4. EAC's fee-and-PlanA() transfer mechanics create additional reserve movement and amplify the price effect.
  5. The attacker sells the now-more-valuable EAC back into the market, repays the flashloan, and converts the residual USDT into WBNB.

The flashloan is not the root cause. It is only a capital source. The protocol failure is that the treasury buy itself was exposed to arbitrary callers.

5. Adversary Flow Analysis

The adversary lifecycle is visible in a single transaction:

EOA 0x27e981... -> helper 0x20dcf125...
helper -> DODO flashLoan(0, 300000e18, helper, "EAC")
helper -> Pancake router buy USDT -> EAC
helper -> PyramidRelation proxy selector 0xe6a24c3f(victimUsdt)
proxy/implementation -> USDT approve + router swap using treasury funds
helper -> Pancake router sell EAC -> USDT
helper -> repay DODO pool
helper -> swap residual USDT -> WBNB

The trace and balance diff show that the helper repaid the pool and the attacker EOA finished with native profit. The native balance delta for the attacker EOA is:

{
  "address": "0x27e981348c2d1f5b2227c182a9d0ed46eed84946",
  "before_wei": "95522250000000000",
  "after_wei": "29296694639490809406",
  "delta_wei": "29201172389490809406"
}

This matches the narrative that the attacker realized 29.201172389490809406 BNB net profit after gas.

6. Impact & Losses

The direct deterministic victim loss was the complete depletion of the PyramidRelation treasury's USDT balance:

{
  "token_symbol": "USDT",
  "amount": "14300000000000000000000",
  "decimal": 18
}

In user-display terms, that is 14300 BNB Chain USDT units, because this deployed USDT contract uses 18 decimals. The attacker converted part of that extracted value into 29.201172389490809406 BNB net profit after paying gas.

Affected parties were the PyramidRelation treasury and, indirectly, the EAC market participants exposed to the induced price dislocation.

7. References

  1. Seed transaction: 0x477f9ee698ac8ae800ffa012ab52fd8de39b58996245c5e39a4233c1ae5f1baa
  2. Attacker EOA: 0x27e981348c2d1f5b2227c182a9d0ed46eed84946
  3. Attacker helper: 0x20dcf125f0563417d257b98a116c3fea4f0b2db2
  4. Victim proxy: 0xa08a40e0f11090dcb09967973df82040bff63561
  5. Delegated implementation observed in trace: 0xb803ed66ab449d80ed12cacf83eae5147fdc6922
  6. DODO USDT pool: 0x26d0c625e5f5d6de034495fbde1f6e9377185618
  7. EAC token: 0x64f291de10ecd36d5f7b64aaebc70943cface28e
  8. Supporting artifacts:
/workspace/session/artifacts/collector/seed/56/0x477f9ee698ac8ae800ffa012ab52fd8de39b58996245c5e39a4233c1ae5f1baa/metadata.json
/workspace/session/artifacts/collector/seed/56/0x477f9ee698ac8ae800ffa012ab52fd8de39b58996245c5e39a4233c1ae5f1baa/balance_diff.json
/workspace/session/artifacts/collector/seed/56/0x477f9ee698ac8ae800ffa012ab52fd8de39b58996245c5e39a4233c1ae5f1baa/trace.cast.log
/workspace/session/artifacts/collector/seed/56/0x64f291de10ecd36d5f7b64aaebc70943cface28e/src/Contract.sol
/workspace/session/artifacts/collector/seed/56/0x89e75e1fcf32b8d2b6c7d3a40c5bbf8fddb93b08/src/Contract.sol
/workspace/session/artifacts/auditor/iter_1/pyramid_relation_impl_evidence.txt