We do not have a reliable USD price for the recorded assets yet.
0x86efdf5b45ee833e696be15bddf0b60f6c449f73a45e39edd4838d9ece3162230x3f648151f5d591718327aa27d2ee25edf1b435d8BSC0x09806632aabc99ae43a8644f336f38f9f559b26bBSCOn BNB Chain block 86181136, transaction 0x86efdf5b45ee833e696be15bddf0b60f6c449f73a45e39edd4838d9ece316223 let an unprivileged attacker use public Pancake flash swaps and Goose VaultChef pool 60 to extract value from Goose Finance. The attacker borrowed 10,170,000 EGG across two public pairs, ran two deposit/withdraw cycles against VaultChef, repaid the flash swaps, sold the leftover EGG through public liquidity, and finished with 13042428046671630412 wei of net BNB profit after gas. The economic loss to the protocol was 2656027385603987181220091 raw EGG units.
The root cause was stale share accounting in StrategyGooseEgg at 0x09806632aabc99ae43a8644f336f38f9f559b26b. New shares were minted against wantLockedTotal before _farm() synchronized the strategy's already-controlled idle EGG and pending MasterChef rewards into that accounting variable. The attacker therefore minted underpriced shares and then redeemed those shares against a larger post-farm asset base.
Goose VaultChef at 0x3f648151f5d591718327aa27d2ee25edf1b435d8 manages pool 60 and delegates its EGG strategy to StrategyGooseEgg. VaultChef tracks each user by shares, while the strategy tracks aggregate assets with and . User redemptions are valued from the ratio .
wantLockedTotalsharesTotaluser.shares * wantLockedTotal / sharesTotalStrategyGooseEgg stakes WrappedEGG in Goose MasterChef pid 25 at 0xe70e9185f5ea7ba3c5d63705784d8563017f2e57. That design creates three economically relevant EGG buckets:
wantLockedTotal.Immediately before the exploit at block 86181135, public RPC state showed:
wantLockedTotal(strategy) = 5284234511247103961542905
EGG.balanceOf(strategy) = 3689861478111647027651406
MasterChef.pendingEgg(25, strategy) = 359560906866936595304278
VaultChef.poolInfo(60).strat = 0x09806632aabc99ae43a8644f336f38f9f559b26b
Those values were enough for any searcher to see that Goose was economically controlling more EGG than it was using for share pricing.
This was an ATTACK category accounting exploit, not an MEV-only arbitrage. The broken invariant is straightforward: newly minted shares must be priced against the strategy's total managed EGG, not against only the subset already stored in wantLockedTotal. StrategyGooseEgg violated that invariant by computing sharesAdded first and calling _farm() second. _farm() then swept all idle EGG on the strategy address into WrappedEGG, increased wantLockedTotal, and deposited the full amount into MasterChef. VaultChef later redeemed the attacker's shares against that larger wantLockedTotal, so the attacker withdrew more EGG than was originally deposited. The exploit remained anyone-can-take because the stale asset buckets, the public pool mapping, the flash-swap liquidity, and the liquidation venues were all permissionless and publicly observable.
The vulnerable components were:
VaultChef pool 60 at 0x3f648151f5d591718327aa27d2ee25edf1b435d8StrategyGooseEgg at 0x09806632aabc99ae43a8644f336f38f9f559b26bMasterChef pid 25 at 0xe70e9185f5ea7ba3c5d63705784d8563017f2e57The violated security principles were:
The verified StrategyGooseEgg source contains the core breakpoint:
function _deposit(address _userAddress, uint256 _wantAmt) internal returns (uint256) {
uint256 sharesAdded = _wantAmt;
if (wantLockedTotal > 0) {
sharesAdded = _wantAmt
.mul(sharesTotal)
.mul(entranceFeeFactor)
.div(wantLockedTotal)
.div(entranceFeeFactorMax);
}
sharesTotal = sharesTotal.add(sharesAdded);
_farm();
return sharesAdded;
}
function _farm() internal {
uint256 wantAmt = IERC20(eggAddress).balanceOf(address(this));
if (wantAmt == 0) return;
wrapEgg(wantAmt);
wantLockedTotal = wantLockedTotal.add(wantAmt);
IGooseMasterChef(gooseChef).deposit(pid, wantAmt);
}
_deposit() prices shares from _wantAmt, sharesTotal, and wantLockedTotal, but _farm() only updates wantLockedTotal afterwards. If the strategy already holds idle EGG or can immediately harvest pending EGG, the new depositor buys into an understated denominator.
VaultChef's verified source shows the matching redemption path:
uint256 wantLockedTotal = IStrategy(pool.strat).wantLockedTotal();
uint256 sharesTotal = IStrategy(pool.strat).sharesTotal();
uint256 amount = user.shares.mul(wantLockedTotal).div(sharesTotal);
if (_wantAmt > amount) {
_wantAmt = amount;
}
uint256 sharesRemoved = IStrategy(pool.strat).withdraw(msg.sender, _wantAmt);
The strategy's external MasterChef position explains why pending rewards matter. MasterChef::deposit and MasterChef::withdraw both settle accumulated EGG rewards to the strategy address before updating the staking balance, so pending EGG becomes another untracked asset bucket unless Goose accounts for it before share issuance.
The collected exploit trace shows the mismatch in action. In human terms, the attacker borrowed EGG, deposited into VaultChef, and the strategy immediately swept not just the attacker deposit but also the pre-existing idle balance:
VaultChef::deposit(60, 10170000000000000000000000)
StrategyGooseEgg::deposit(..., 10170000000000000000000000)
MasterChef::deposit(25, 13859861478111647027651406)
Transfer(from: MasterChef, to: StrategyGooseEgg, value: 359561000931595130013976)
VaultChef::withdraw(60, uint256(-1))
StrategyGooseEgg::withdraw(..., 12593884246852374493680720)
The first MasterChef::deposit amount, 13859861478111647027651406, is larger than the attacker's 10170000000000000000000000 EGG deposit because it includes the strategy's pre-existing idle EGG. MasterChef also transferred 359561000931595130013976 EGG rewards back to the strategy during that same cycle. The attacker then withdrew 12593884246852374493680720 EGG, already more than the original flash-borrowed amount.
The second cycle repeated the same pattern with the newly harvested rewards:
12593884246852374493680720_farm() stake: 1295344524778396962369469612826027479668645715929789At that point the attacker had extracted the stale idle bucket plus the reward bucket into withdrawable value. The exploit was deterministic because every required condition was public:
60's public mapping to the strategy;The adversary cluster visible on-chain consisted of:
0x1E959Ce51E70FF93278c470Bf05a0f09b3c850de, the transaction sender and final BNB profit recipient0x978447c289DAf3dD5e2615AF97E93a3bC4f53562, an attacker-deployed wrapper0xd7E9763D79Eb9011e518129c79455E7eA65e0Cbf, the attacker-controlled exploit contractThe end-to-end flow in tx 0x86efdf5b45ee833e696be15bddf0b60f6c449f73a45e39edd4838d9ece316223 was:
5070000000000000000000000 EGG from the public EGG/BUSD pair 0x19e7cbecdd23a16dfa5573df54d98f7caae03019 and 5100000000000000000000000 EGG from the public EGG/WBNB pair 0xd1b59d11316e87c3a0a069e80f590ba35cd8d8d3.60, withdrew all, deposited the returned EGG again, and withdrew again. Both cycles were permissionless uses of public Goose interfaces.5085255767301905717151455 EGG to the EGG/BUSD pair and 5115346038114343029087262 EGG to the EGG/WBNB pair, sold the remaining EGG through the public EGG/WBNB, EGG/BUSD, and BUSD/WBNB pairs, converted to WBNB/BNB, and transferred the proceeds back to the sender.The success predicate was purely profit-based. The attacker's externally owned account went from 9975000000000000 wei before the transaction to 13052403046671630412 wei after it, a net native balance gain of 13042428046671630412 wei while paying 101601050000000 wei in gas.
The incident transferred value from Goose vault depositors to the attacker by shrinking the strategy's real EGG backing while leaving the attacker with liquidated proceeds. The measured protocol loss was:
[
{
"token_symbol": "EGG",
"amount": "2656027385603987181220091",
"decimal": 18
}
]
In state terms, the strategy's public managed EGG position dropped from 9333656896225687584498589 raw units before the exploit to 6677629510621700403278498 raw units after the exploit. The attacker monetized that depletion into BNB through public Pancake liquidity, so the loss was both realized and immediately extractable.
https://bscscan.com/tx/0x86efdf5b45ee833e696be15bddf0b60f6c449f73a45e39edd4838d9ece3162230x86efdf5b45ee833e696be15bddf0b60f6c449f73a45e39edd4838d9ece316223VaultChef source: https://bscscan.com/address/0x3f648151f5d591718327aa27d2ee25edf1b435d8#codeStrategyGooseEgg source: https://bscscan.com/address/0x09806632aabc99ae43a8644f336f38f9f559b26b#codeMasterChef source: https://bscscan.com/address/0xe70e9185f5ea7ba3c5d63705784d8563017f2e57#code0x19e7cbecdd23a16dfa5573df54d98f7caae03019, EGG/WBNB 0xd1b59d11316e87c3a0a069e80f590ba35cd8d8d3, BUSD/WBNB 0x1b96b92314c44b159149f7e0303511fb2fc4774f