November 2, 2026
The Moonwell Exploit: An $8.7M Attack That Bypassed a Supply Cap
How the attack worked and what AutoProver found.
Author:
Lilian CariouOn August 27, 2026, an attacker borrowed $11M of cbBTC, WETH, USDC and wstETH from Moonwell, a lending protocol on Base, against a MAMO deposit worth about $160K at the morning's price. About 8.7M USDC of the proceeds left Base the same morning, the $8.7M in most reports.
The flaw is in how the market counts MAMO. A deposit receipt, mMAMO, is worth the market's MAMO balance divided by the number of receipts, and anyone can raise that balance by sending MAMO straight to the contract. The market had a supply cap of 20M MAMO, but the post-mortem by Anthias Labs, Moonwell's risk manager, sums it up: "The 20 million MAMO supply cap checked formal mint inputs." So the attacker deposited 15M MAMO, then sent 53M more directly to the contract. Every mMAMO became worth 3.7 times as much, and the cap never ran. A pumped MAMO price did the rest.
The same pattern hit Tectonic on Cronos three days later, and Certora’s analysis of that attack proposed a fix: keep cash in a ledger instead of reading the token balance. We ran AutoProver, Certora’s agent that writes and proves specifications, on Moonwell’s market as the code stood on August 24, the last commit before the attack. The run took place in October, after the attack, with a short threat model for lending markets. AutoProver wrote a rule saying that a transfer which never calls the market must not change what suppliers are owed, the number the supply cap is checked against. The Certora Prover reports that rule violated on the deployed contract and verified with the cash ledger, under the assumptions listed below.
How a $160K deposit became $11M of loans
The attacker turned a $160K deposit into $11M of loans by inflating its collateral in two ways: sending MAMO straight to the market and pumping the MAMO price.
From 07:04 UTC the attacker supplied 15,089,595 MAMO to the market, worth about $160K at the morning’s price of $0.0106, and received about 736M mMAMO, roughly three quarters of all mMAMO in existence. Each deposit passed the supply cap check because the market stayed under 20M MAMO.
The rest of the attack overlapped. From about 09:11 the MAMO/USD feed climbed as the attacker bought MAMO on thin decentralized exchange liquidity, including Aerodrome’s MAMO/USDC pool. Anthias Labs puts the gross purchases at about $7.5M, much of it borrowed assets recycled during the operation. The first borrow came at 08:43 and more followed from 09:16, so some loans were taken before the direct transfers.
At 09:19 and 09:21 the attacker sent 35M MAMO and 18M MAMO to the mMAMO contract with plain token transfers. No mMAMO was created and no deposit function ran, so the cap check never executed. The value of one mMAMO rose from 0.0205 to 0.0755 MAMO, 3.7 times as much, and the attacker’s 736M mMAMO now stood for about 55M MAMO instead of 15M, almost three times the cap on its own.
The feed peaked at $0.43 at 09:28, and Moonwell accepted a price of $0.40 at 09:29. Moonwell values collateral as the number of mMAMO, times the MAMO each one stands for, times the MAMO price. At $0.40, 55M MAMO was about $22M of collateral, and the 50% collateral factor allowed about $11M of loans. The attacker made 18 borrows of cbBTC, WETH, USDC and wstETH between 08:43 and 09:30, then bridged 8.7M USDC from Base to Ethereum through Circle’s CCTP in two burns at 09:41 and 09:42. Liquidators seized almost all of the attacker’s mMAMO, but by then the MAMO price was back near $0.01 and most of the debt it backed was not repaid.
Both halves were needed for $11M. Without the direct transfers, the attacker’s collateral stays at 15M MAMO, inside the cap. Without the price pump, 55M MAMO at $0.0106 is worth about $590K.
Why did Moonwell’s supply cap not stop the attack?
The cap was checked only when someone deposited, and sending MAMO straight to the contract is not a deposit, so the check never ran.
Moonwell is a fork of Compound v2. The value of one mMAMO, its exchange rate, is computed in MToken.sol from four numbers:
Moonwell's own functions write three of them. The fourth, totalCash, is read from the token every time, in MErc20.sol:
So any MAMO that lands in the contract counts, whether it arrived through a deposit or not. The supply cap is checked in the Comptroller, the contract that approves each action, in mintAllowed, which runs before a deposit and only then:
The cap measures the right number, everything the market owes its suppliers, but only when someone deposits. A MAMO transfer calls the MAMO token, not Moonwell, so no Moonwell check can run. After the two transfers the market would have refused any new deposit. It had nothing to refuse.
The cap was there for a reason. MIP-B48, the October 2025 proposal that listed MAMO, set it alongside a note from Anthias Labs that "around $200k of MAMO can be swapped instantly for stables while slippage stays below the liquidation bonus of 7%." On the morning of the attack, 20M MAMO was worth about $212K. The cap kept MAMO collateral close to what liquidators could sell, and the transfers took it to almost three times that.
Moonwell exploit timeline
The attack ran for under three hours on August 27, 2026, from the first deposit at 07:04 UTC to the second bridge transfer at 09:42 UTC.
All times are from the Anthias post-mortem.
August 27, 06:09 UTC
A linked account sends gas money to the attacker's main account, 0x719e...919D.
07:04 UTC
First MAMO deposit into Moonwell.
08:43 UTC
First borrow.
09:19 and 09:21 UTC
The two direct transfers, 53M MAMO in total.
09:28 UTC
The MAMO/USD feed peaks at $0.43.
09:30 UTC
Last borrow, 990K USDC, and first liquidation.
09:41 and 09:42 UTC
Two CCTP burns of 4.36M USDC each.
10:53 UTC
Moonwell cuts borrow caps to 1 wei.
11:09 UTC
Moonwell cuts the MAMO supply cap to 1 wei.
The borrowing took 47 minutes. The bridge transfers went out while liquidators were still seizing mMAMO.
Is the Moonwell exploit a donation attack on a Compound fork?
Yes. Sending the collateral token straight to a Compound v2 fork to inflate its exchange rate is a donation attack, and Hundred Finance, Venus and Tectonic were hit the same way.
The attack class was already written down in Moonwell's own repository. A test added in 2023 reproduces the 2023 Hundred Finance exploit on a Moonwell market. It puts 100 tokens straight into the market's balance, and the comment after it reads: "We can now borrow everything in the markets due to the massively inflated exchange rate." Both tests in the file make that borrow, and it succeeds. What they check is the step after it: that the attacker cannot pull the donation back out through redeemUnderlying. The MAMO attacker never needed that step. Borrowing against the inflated collateral and leaving the debt behind was enough.
Venus Protocol, another Compound v2 fork, lost to the same sequence on March 15, 2026. According to Rekt, the attacker deposited 12M THE, 84% of the cap, then sent THE directly to the market, taking the position to 53M, 367% of the cap, at its peak, and left Venus with $2.2M of bad debt. Three days after Moonwell, Tectonic was hit by the same combination of a direct transfer and a pumped price.
A test checks the scenario someone wrote down. Whether every way into totalCash is covered is a different question, the gap between testing and formal verification.
What did AutoProver find in Moonwell’s MAMO market?
In a run after the attack, AutoProver wrote a rule that the Prover shows is violated by the deployed contract: sending MAMO straight to the market changes what suppliers are owed.
AutoProver worked on Moonwell's repository at 3b32d53, merged on August 24, 2026, the last commit before the attack. Its target was the contract the mMAMO market runs on Base, MErc20Delegate.
AutoProver ranked 150 candidate properties for the market. One of them, supply_cap_bypass_and_dos_via_donation, asks "whether suppliers' claim can exceed the supply cap". It then drafted 13 properties for the supply and redeem functions and wrote them as rules in CVL, the Certora Prover's specification language. The run used comprehensive mode and cost about $400.
The rule that matches the attack is the first one in its market accounting file. In plain words: put MAMO into the market without calling any market function, and what suppliers are owed must not change. AutoProver wrote it this way:
supplierClaim() is getCash() + totalBorrows - totalReserves, the number the Comptroller compares with the cap. The donation adds MAMO to the market's balance without calling Moonwell, which is what the attacker's two transfers did.
What formal verification can establish about supply caps
Once the market keeps cash in its own ledger, formal verification can establish that no direct transfer changes what suppliers are owed, under stated assumptions about the token and the oracle.
The fix comes from our Tectonic analysis: keep cash in a ledger that only the market's own transfers move, so MAMO sent to the contract no longer changes totalCash or the exchange rate. Moonwell has not changed how its markets count cash, it set the MAMO supply cap and the borrow caps to 1 wei. So the fixed contract below is ours:
A live market would also need a one-time admin call that sets the ledger to the current balance.
On the deployed code, the Prover finds a counterexample. In a market where suppliers are owed 1 wei of MAMO, someone sends 1 wei straight to the contract. Suppliers are now owed 2, and no cap check ran. That is the attack, at the smallest scale.
With the ledger, the Prover verifies the rule: no direct transfer can change what suppliers are owed. The runs assume MAMO is a standard ERC-20 token that moves exactly the amount requested and never calls back into the market, and they let the price oracle, the interest rate model and other markets return any value.
Status as of October 28, 2026
Borrowing on Moonwell's Base markets has been capped at 1 wei since 10:53 UTC on August 27, and MAMO deposits since 11:09. MIP-X66, executed in early September, used about $246K of protocol reserves from Base and OP Mainnet to repay bad debt in the USDC market and changed interest rate models so the bad debt accrues about $50K a month instead of $339K, by Anthias's estimate. MIP-X69 set MAMO's collateral factor to 0% on Base from October 17, after missing quorum once.
Recovery for suppliers is still in progress. On August 31 a MAMO supplier reported that the market held 729.5 MAMO of liquidity against 1.26M MAMO supplied. Moonwell has said it is working to recover the stolen funds, and depositors have asked on the forum for a recovery plan and fair withdrawal rules.
Key takeaways from the Moonwell exploit
A cap checked at one entry point only limits that entry point. Moonwell's cap measured the right number, but only on deposits, while that number could grow through a plain transfer that never calls Moonwell. A market can only cap what it counts, so the fix is to stop counting tokens it did not receive through its own functions.
The same pattern hit three Compound forks in 2026: Venus on March 15, Moonwell on August 27 and Tectonic on August 30. Each time the attacker sent the collateral token straight to the market and pushed the price of a thinly traded collateral token. The property that catches the direct transfer fits in one sentence: a transfer that never calls the market must not change what suppliers are owed.
--
CERTORA
Try Certora Prover, the free formal verification tool.
See what AutoProver automates, AI-assisted specification generation built on top of Prover.
Get a Certora smart contract audit, manual review combined with formal methods.
Explore Certora's formal verification capabilities.
Provable is a Certora production.
