PancakeBunny Reward-Mint / LP Price Manipulation Exploit (2021-05-19)
- Name: PancakeBunny reward-mint / LP price manipulation exploit
- Date: 2021-05-19
- Protocol: PancakeBunny
- Chain: BNB Smart Chain
- Category: oracle manipulation / LP-token mispricing / reward-mint inflation / flash-loan economic exploit
- Loss: attacker profit of about 114,631 WBNB; widely reported protocol / market impact around $45 million after the attacker dumped the newly minted BUNNY
- Summary: The attacker first staged a dust-sized WBNB-BUSDT Flip Vault position, waited until a keeper
harvest()made that position show a tiny positiveearned()balance, and then used a bundle of eight flash loans to distort PancakeSwap liquidity and abuse PancakeBunny’s LP valuation logic insidePriceCalculatorBSCV1andBunnyMinterV2. By minting a huge amount of WBNB-BUSDT LP directly to the pair contract, then inflating the WBNB side of the relevant PancakeSwap v1 pool, the attacker made PancakeBunny treat a microscopic performance-fee claim as if it had generated an enormous amount of BNB-denominated value. That letgetReward()mint about 6.97 million BUNNY to the attacker, who immediately sold the tokens for WBNB and repaid the flash loans. - Trigger / entry point:
- The attacker first seeded PancakeBunny’s
VaultFlipToFlipWBNB-BUSDT vault with a tiny LP position so the account would later be eligible to callgetReward(). - That seed alone was not enough: the vault only exposed a positive
earned()balance after a keeper-triggeredharvest()updated strategy accounting, so the attacker staged the position in an earlier transaction and came back once rewards were live. - PancakeBunny’s reward path sent the claimed LP-fee amount into
BunnyMinterV2::mintForV2(). mintForV2()routed through_zapAssetsToBunnyBNB()andPriceCalculatorBSCV1::valueOfAsset(), which trusted AMM reserve state and a simplistic LP valuation formula during the same manipulated transaction.- The valuation path effectively priced a PancakeSwap LP token as
2 * WBNB reserve / totalSupply, making it easy to overstate value by temporarily stuffing WBNB into the relevant pool.
- The attacker first seeded PancakeBunny’s
- Root cause:
- PancakeBunny treated instantaneous AMM reserves as trustworthy LP-token value for solvency-critical reward minting.
- The protocol let attacker-controlled liquidity minting and reserve manipulation feed directly into BUNNY issuance.
BunnyMinterV2also burned the entire LP balance held by the contract duringremoveLiquidity(), so attacker-supplied LP tokens minted to the pair contract amplified the assets flowing through the reward path.- In short: PancakeBunny converted a manipulable pool state into freshly minted protocol tokens with no depth check, no manipulation-resistant oracle, and no isolation between fee accounting and externally gameable reserve math.
- Exploit path:
- In a staging transaction
0x88fcffc3256faac76cde4bbd0df6ea3603b1438a5a0409b2e2b91e7c2ba3371a, the attacker zapped1 BNBinto the WBNB-BUSDT v2 Flip Vault and deposited about9.2751LP tokens intoVaultFlipToFlipso the address would later have a claimable position. - After a keeper
harvest()updated vault accounting, that staged position showed only about0.000521785526032378LP ofearned()profit, implying a performance-fee slice of roughly0.000156535657809713LP. The later over-mint therefore did not come from a large real fee claim; it came from how PancakeBunny handled and valued that tiny claim. - The attacker then funded the main exploit transaction with eight flash loans: seven large WBNB loans from PancakeSwap pools and one
2,961,750 USDTloan from ForTube. - Inside the exploit bundle, the attacker minted about
144,445WBNB-BUSDT LP tokens directly to the PancakeSwap v2 pair contract by adding2,961,750 USDTand about7,744 WBNBas liquidity. - The attacker then swapped about
2,315,631 WBNBfor about3,826,047 USDTthrough the thinner PancakeSwap v1 WBNB-USDT pool, sharply inflating the WBNB reserve state used by PancakeBunny’s price logic. - The attacker called
VaultFlipToFlip::getReward(). That transferred only the tiny performance-fee LP amount intoBunnyMinterV2::mintForV2(). - During
_zapAssetsToBunnyBNB(), PancakeBunny’s router path calledremoveLiquidity()in a way that burned the pair contract’s full LP balance held for the minter flow, including the large LP position the attacker had preloaded into the pair contract earlier in the same transaction. That returned about2,961,750 USDTand7,744 WBNBto the minter path from what should have been a microscopic fee conversion. PriceCalculatorBSCV1::valueOfAsset()then valued the resulting BUNNY-BNB LP position using the manipulated WBNB reserve, making the fee contribution appear worth roughly2,324,152 BNB.amountBunnyToMint()turned that fake contribution into about6,972,455 BUNNYfor the attacker, plus separate protocol-side minting to the dev address.- The attacker dumped the newly minted BUNNY across PancakeSwap markets, repaid the flash loans, and kept about
114,631 WBNB.
- In a staging transaction
- What the attacker needed to be true:
- PancakeBunny had to rely on spot AMM reserves from shallow / manipulable pools instead of a manipulation-resistant oracle.
- Reward minting had to depend directly on that LP valuation rather than on realized fee value over time.
- The vault needed to expose a nonzero
earned()balance after a keeper harvest sogetReward()would enter the mint path at all. - The minter’s liquidity-removal path had to sweep far more LP exposure than the tiny fee amount alone should have represented.
- The attacker needed enough flash-loan liquidity to dominate the relevant PancakeSwap pools for one transaction.
- BUNNY markets needed enough exit liquidity that the freshly minted reward tokens could be sold before prices fully collapsed.
- Technical anatomy worth remembering:
- This was not a borrow-against-collateral oracle attack. It was a reward-mint attack: fake LP value became protocol-token issuance, and the attacker monetized the printed BUNNY by selling it.
- The exploit required a timing precondition many summaries skip: the attacker first needed a keeper harvest so a dust-sized vault deposit actually registered positive
earned()fees and could enter the minter path. - The exploit had two amplifiers, not one. Manipulated AMM reserves overstated LP value, and the minter’s liquidity-removal flow implicitly included the attacker’s huge LP position minted to the pair contract.
- The vulnerable formula was economically naive: doubling one reserve side of an LP pool is not a safe valuation method when the reserve itself can be flash-loan distorted.
- PancakeBunny’s own token became the extraction medium. Once the protocol over-minted BUNNY, market-selling turned accounting fiction into real WBNB.
- Representative transactions and addresses:
- Main exploit transaction:
0x897c2de73dd55d7701e1b69ffb3a17b0f4801ced88b0c75fe1551c5fcce6a979 - Staging deposit transaction for the tiny LP position:
0x88fcffc3256faac76cde4bbd0df6ea3603b1438a5a0409b2e2b91e7c2ba3371a - Attacker EOA:
0xa0acc61547f6bd066f7c9663c17a312b6ad7e187 - Attacker contract:
0xcc598232a75fb1b361510bce4ca39d7bc39cf498 - Staged vault (
VaultFlipToFlip, WBNB-BUSDT):0xd415e6caa8af7cc17b7abd872a42d5f2c90838ea - Vulnerable minter (
BunnyMinterV2):0x819eea71d3f93bb604816f1797d4828c90219b5d - Vulnerable price helper (
PriceCalculatorBSCV1):0x81ef2bc1e02fee5414e46accc6ae14d833eebba0
- Main exploit transaction:
- Response / mitigation:
- PancakeBunny paused deposits and withdrawals after the exploit and later published an incident timeline blaming a flash-loan-driven pricing exploit.
- The incident became a reference case for why LP-token pricing is an oracle problem, not just a helper-function implementation detail.
- It also preserved a useful review lesson for fee and emission code: a dust-sized real entitlement can still unlock a catastrophic mint if the downstream conversion path accidentally sweeps unrelated LP exposure and values it off attacker-authored reserves.
- The attack reinforced a recurring lesson from Warp, Cheese Bank, and related incidents: reserve-based LP valuation is dangerous when the same transaction can create the reserve state being priced.
Three issuance-truth promotions this incident collapsed
-
A tiny real fee entitlement existed at all
- The attacker did not begin with a fake vault position. They first staged a legitimate dust-sized WBNB-BUSDT Flip Vault deposit, then waited for a keeper
harvest()soearned()became slightly positive. - That meant PancakeBunny had one authentic accounting fact to work with: a microscopic performance-fee LP claim really was eligible to enter
getReward().
- The attacker did not begin with a fake vault position. They first staged a legitimate dust-sized WBNB-BUSDT Flip Vault deposit, then waited for a keeper
-
That tiny claim was still promoted into a huge BNB-denominated contribution story
BunnyMinterV2::mintForV2()and_zapAssetsToBunnyBNB()let the fee-sized claim inherit far more inventory than it should have controlled, becauseremoveLiquidity()effectively burned the pair contract’s whole LP balance, including the attacker’s preloaded144,445LP tokens.PriceCalculatorBSCV1::valueOfAsset()then valued the resulting BUNNY-BNB LP against attacker-inflated WBNB reserves, promoting a claim that started as roughly0.0001565LP of fees into a published contribution worth about2,324,152 BNB.
-
That published contribution truth still deserved immediate BUNNY mint authority
- Once the manipulated helper path said the attacker had contributed BNB-scale value,
amountBunnyToMint()treated that mark as canonical issuance truth and minted about6,972,455 BUNNY. - The attacker could then dump that freshly printed supply into external liquidity, turning PancakeBunny’s internally authored valuation fiction into real
114,631 WBNBprofit.
- Once the manipulated helper path said the attacker had contributed BNB-scale value,
The durable lesson is that a real fee entitlement exists, that entitlement's conversion path still defines canonical contribution value, and that published contribution still deserves immediate reward-token mint authority are three different promotions. PancakeBunny failed because one dust-sized honest claim was silently allowed to pass all three.
Pattern tags
- oracle-manipulation
- lp-token-oracle-mispricing
- reserve-backed-claim-truth-security-object
- internal-mark-publication-quarantine-and-reserve-spend-separation
- PancakeBunny’s preserved shape is sharper than generic
flash-loan oracle attack: a dust-sized real fee entitlement entered a reward path that both swept attacker-preloaded LP exposure and then priced the resulting position off attacker-authored AMM reserves. - The live failure was therefore
same-transaction reserve print became issuance truth. LP helper output, fee conversion, and BUNNY mint quantity were one joined balance-sheet object even though the code treated them like ordinary helper math.
Why the exploit worked
- The attacker only needed a tiny real claim to enter the reward path. The staging transaction and later keeper
harvest()created a legitimate but microscopicearned()balance, so PancakeBunny’s own fee-accounting logic opened the door intoBunnyMinterV2::mintForV2()without requiring a large honest profit first. - Once inside that path, PancakeBunny multiplied the mistake twice. First,
removeLiquidity()in_zapAssetsToBunnyBNB()effectively burned the pair contract’s full LP balance held for the minter flow, so the attacker could preload a huge WBNB-BUSDT LP position into the pair and have that unrelated inventory ride along with the tiny performance-fee claim. Second,PriceCalculatorBSCV1::valueOfAsset()then treated manipulated WBNB reserves as if they were fair LP-token value. - The decisive publication boundary was therefore internal, not external. PancakeBunny was not merely consuming a bad market price from somewhere else; its own reward machinery turned attacker-shaped pool state into canonical
valueInBNB, then turned that number directly into fresh BUNNY issuance. - The reserve formula was economically underdesigned for this role. Pricing an LP token as roughly
2 * WBNB reserve / totalSupplyis already fragile when reserve state can be flash-loan distorted, but it becomes catastrophic when the same transaction can also decide how much LP inventory the minter path will unwrap and how much newly minted protocol token supply that value will authorize. - This is why the exploit is more useful than a generic
oracle manipulationlabel suggests: the real break was not onlyspot too easy to move, butclaim conversion, LP valuation, and token issuance all trusted the same attacker-authored state object at once.
Detection and audit pivots
- Trace every path where a farm, vault, or fee-minter converts LP-token value into newly minted protocol liabilities. If
earned(),performanceFee, or another small accounting claim can unlock a downstream conversion that touches a manipulable LP oracle, treat that reward path as solvency-critical. - Ask what exact LP inventory
removeLiquidity()or equivalent helper calls can consume. PancakeBunny paid because a tiny fee-denominated LP amount implicitly swept a much larger LP balance the attacker had pre-positioned into the pair contract; auditors should explicitly testclaim-sized input, pair-sized burn outputmismatches. - Review whether the protocol’s LP valuation helper consumes same-transaction reserve state, especially reserve state from a thin or attacker-dominable pool. If the answer is yes, ask whether the published mark can immediately mint debt, rewards, or governance token supply before any delay, averaging, or independent reserve check narrows the claim.
- Diff the reward path by economic object, not function name.
PriceCalculator,_zapAssetsToBunnyBNB(), router liquidity burns, andamountBunnyToMint()were one issuance boundary even though they lived in separate helpers. - Fuzz for
small real entitlement -> huge synthetic conversioncases. The dangerous test is not onlycan price move?butcan a dust-sized honest claim unlock a downstream conversion that accidentally adopts attacker-supplied inventory or attacker-shaped reserves? - Treat protocol-token reward mints like credit extension. If newly minted BUNNY can be sold into meaningful exit liquidity immediately, then the pricing and conversion logic feeding that mint deserves the same adversarial review as collateral admission or borrow authorization.
Failure-prevention checklist
- Keep one bounded claim object from fee accrual to reward issuance. A tiny performance-fee LP claim should never be able to sweep unrelated LP balances or inherit pair-contract inventory that the accounting system did not explicitly authorize.
- Do not price LP tokens for issuance-critical paths from same-transaction spot reserves. Use manipulation-resistant marks, delayed observations, independent reserve vectors, or capped / quarantined conversion paths before those marks can mint transferable protocol supply.
- Make helper contracts prove inventory provenance.
removeLiquidity()or zap helpers should only consume LP tokens that the current frame explicitly transferred in, not ambient or attacker-prepositioned balances sitting at the pair or helper boundary. - Separate publication from spend. If a fresh LP valuation or reserve-derived mark is needed operationally, publish it first and keep mint / issuance rights delayed, capped, or otherwise bounded until the mark has survived an independent check or time boundary.
- Put hard ceilings under reward mints sourced from helper-priced positions: per-claim caps, per-epoch caps, circuit breakers on reserve moves, and sanity checks against historical fee accrual so
tiny real fee -> massive token printcannot complete in one frame. - Test reward and fee paths with the same adversarial rigor as borrow paths. The ability to mint a transferable governance or farm token against an LP mark is a balance-sheet action, not harmless emissions plumbing.
- For LP-token valuation, require explicit answers to
what reserve vector counts,what liquidity can actually be unwound at that size, andwhat same-state manipulations are excluded before this mark can authorize issuance?
Audit prompts
- Can a tiny real
earned()or fee amount unlock a helper path that unwraps, swaps, or values far more inventory than the accounting claim itself should control? - Which balances does the minter / zap / router path actually consume at liquidity-removal time: only the frame-local transferred LP amount, or any ambient balance sitting at a pair or helper contract?
- If LP valuation uses reserves, are those reserves thin, directly manipulable, or drawn from the same transaction that also uses the resulting mark to mint protocol tokens?
- What independent bound stops
helper-priced contributionfrom drifting far above historically realized fee value or above the assets that truly entered the system in this frame? - Could an attacker preload LP or underlying assets into a contract the protocol later burns against, causing a claim-sized accounting event to inherit attacker-sized conversion inventory?
- Does the reward path distinguish
protocol recognized a feefromprotocol may now publish a spendable BNB-denominated contribution and mint transferable supply against it, or are those treated as one step? - If the protocol’s own token is the extraction medium, what prevents an attacker from converting an over-mint straight into deeper external reserves before the price helper can normalize?
Lessons that should already be standard
- Reward-mint logic is balance-sheet logic when the reward token is transferable and liquid.
- A helper that prices LP tokens for minting is an oracle whether or not the code calls it one.
Tiny honest entitlementis not a safety property if the downstream conversion path can adopt unrelated balances or attacker-authored pool state.- Same-transaction reserve prints should not become immediate issuance truth.
- Ambient balances at pair, vault, router, or helper contracts are adversarial until proven otherwise.
- If protocol-token issuance depends on an LP mark, reserve math, fee conversion, and mint authorization must be reviewed as one object, not as separate helper functions.
Why this incident matters
- PancakeBunny is a clean example of oracle manipulation turning into protocol-token over-minting rather than direct borrowing.
- It shows that
rewardpaths can be as solvency-critical as lending paths when they mint a transferrable governance or farm token against manipulable inputs. - It broadens the oracle-manipulation corpus beyond collateral valuation and into fee-accounting / reward-issuance logic.
- It also preserves a sharper design lesson than
don't use spot prices: PancakeBunny let one same-transaction LP mark become both reward-conversion truth and protocol-token issuance truth.
Internal linkages
- Core recurring pattern: oracle-manipulation.
- Sharper subpattern: lp-token-oracle-mispricing.
- Positive-design companion: reserve-backed-claim-truth-security-object — the healthier question is what exact reserve-backed object should have fused
real fee earned,LP inventory authorized for conversion, andBUNNY amount allowed to mintbefore any helper path could spend against the claim. - Positive-design companion: internal-mark-publication-quarantine-and-reserve-spend-separation — useful when the sharper follow-up is why attacker-shaped same-transaction reserve state should not have become immediate issuance authority for a transferable protocol token.
Control surface
- The leverage sat in PancakeBunny’s LP pricing helper, the minter path that turned fee accounting into fresh BUNNY issuance, and the protocol’s willingness to treat same-transaction AMM reserve state as economic truth.
- PancakeBunny did not just misread a market. It let a flash-loaned pool state define how much of its own token supply to print.
Sources
- https://rekt.news/pancakebunny-rekt
- https://cmichel.io/bsc-pancake-bunny-exploit-post-mortem/
- https://peckshield.medium.com/pancakebunny-incident-root-cause-analysis-7099f413cc9b
- https://pancakebunny.medium.com/hello-bunny-fam-a7bf0c7a07ba
- https://raw.githubusercontent.com/SunWeb3Sec/DeFiHackLabs/main/src/test/2021-05/PancakeBunny_exp.sol
- https://bscscan.com/tx/0x88fcffc3256faac76cde4bbd0df6ea3603b1438a5a0409b2e2b91e7c2ba3371a
- https://bscscan.com/tx/0x897c2de73dd55d7701e1b69ffb3a17b0f4801ced88b0c75fe1551c5fcce6a979
Last reviewed
- 2026-08-03 UTC