Root cause:
`registerNewBondGroup` allowed duplicate bond IDs, and `exchangeEquivalentBonds` counted exception matches instead of unique exception membership. That broke the burn-before-mint assumption for equivalent bond exchange.
Attack flow (simplified):
1) Setup โ register input group 36 as `[07be..., 3a94...]` and output group 37 as `[b14d..., 07be..., 07be...]`
2) Trigger broken logic โ call `exchangeEquivalentBonds(36, 37, 6968565865905, [07be..., 3a94...])`
3) Amplify via protocol mechanics โ both input IDs were exceptions, so no input bond was burned while a non-excepted output bond was minted
4) Extract value โ sell unbacked bonds for 542,144.628604 USDC
The broken invariant is visible here:
```solidity
// Contract.sol โ BondMaker 0xda6fc5625e617bb92f5359921d43321cebc6bef0
function registerNewBondGroup(bytes32[] calldata bondIDs, uint256 maturity) external returns (uint256 bondGroupID) {
require(_assertBondGroup(bondIDs, maturity), "the bond group is not proper");
bondGroupID = _bondGroupList.length;
_bondGroupList.push(BondGroup(bondIDs, maturity));
}
function exchangeEquivalentBonds(...) external returns (bool) {
...
if (exceptionBonds[j] == inputIDs[i]) {
flag = false;
exceptionCount = exceptionCount.add(1);
}
...
if (exceptionBonds[j] == outputIDs[i]) {
flag = false;
exceptionCount = exceptionCount.sub(1);
}
if (flag) _mintBond(outputIDs[i], msg.sender, amount);
}
```
Skylens:
https://t.co/6sx4tm8BSb
Look for the `exchangeEquivalentBonds` calls, duplicated output bond ID, skipped burns, minted bond tokens, and USDC pulls from the victim allowance path.
๐จ Automated Exploit Analysis
Protocol: DeBond
Loss: ~$542,144.63 USDC
Method: duplicate bond ID / exception-counting mint abuse
DeBond was drained because BondMaker treated duplicate bond IDs as valid group members, letting an attacker mint unbacked bonds and sell them into USDC-funded markets.
This is not an isolated bug class: set logic implemented as counters breaks accounting.
Full report: https://t.co/DSsYoMOxO2
Root cause:
Verus Bridge accepted a notarized CCE proof where hashReserveTransfers matched attacker-supplied serializedTransfers, then paid those transfers without validating totalamounts, totalfees, or totalburned against source-chain value.
The broken invariant is visible here:
```solidity
// contracts/MMR/VerusProof.sol โ 0x54E03a1682fd0bB065B669f6296f97028DcFD4Ce
CCEData memory cce = _readCCEFields(firstObj, cceBodyOffset);
if (!(cce.hashReserveTransfers == hashedTransfers &&
cce.sourceSystemID == VERUS &&
cce.destSystemID == VETH &&
cce.destCurrencyID == VETH)) {
revert('CCE information does not checkout');
}
return (packed, cce.exporter, cce.exporter2, cce.exporter3);
```
The verifier checked identity and transfer hash, but not the economic conservation rule behind the payout.
Attack flow (simplified):
1) Setup โ submitter was funded with 0.07 ETH.
2) Trigger broken logic โ setLatestData installed the state root used by the import proof.
3) Amplify via bridge mechanics โ SubmitImports._createImports trusted VerusProof.proveImports and returned numInputs = 8.
4) Extract value โ TokenManager.processTransactions paid 1,137.45281584 ETH, 71.5045915 tBTC, 220,357.02707298 DAI, and other assets to 0xCFd0A20703cD11E0b9f665e1C3F1Ef989C142D54.
Check the trace with Skylens:
https://t.co/RZnmgNBQyl
Look for _createImports -> proveImports -> processTransactions, then the eight decoded payouts to the same recipient.
๐จ Exploit Analysis
Protocol: Verus Bridge
Loss: ~$7.20M
Method: notarized CCE proof validation failure
A bridge import path drained reserves because the Ethereum side trusted a proven transfer hash without enforcing source-side economic totals.
This is the cross-chain failure pattern that keeps recurring: proof validity is not payout validity.
Full report: https://t.co/LdAldOqS6W
You can see the exact failure point in the tx trace ๐
https://t.co/PF65APlIxl
Notice how the bad oracle value is first promoted by `OSM.poke()`, then consumed by `Spotter.poke(BTCB)`, then relied on by `Vat.frob()` to allow both collateral withdrawal and debt expansion.
๐จ Exploit Analysis
A Maker-style lending system broke because an oracle accepted a BTCB price of 1e33 and fed it directly into collateral safety checks.
Result: BTCB was withdrawn, new debt was minted, and the attacker realized ~$761.7k USDT.
This is an oracle-governance failure pattern, not an isolated pricing bug.
https://t.co/WGadu6sxvL
Attack flow (simplified):
1) Setup โ attacker bought and joined 10.743371477925676076 BTCB, then opened debt for 424,003.596994230837818971 BLC
2) Trigger broken logic โ `OSM.poke()` promoted the queued 1e33 BTCB oracle value
3) Amplify via protocol mechanics โ `Spotter.poke(BTCB)` wrote spot = 666666666666666666666666666666666666666666
4) Lock in bad state โ `Vat.frob()` treated 0.006284011757633665 BTCB as enough collateral for 4,925,000 BLC debt
5) Extract value โ withdrew 10.737087466168042411 BTCB and minted/sold 4,500,996.403005769162181029 BLC for 761,696.595696317977899753 USDT
๐จ Exploit Analysis
An AMM pair was drained because a privileged sell path could burn tokens directly from pool reserves, then force the pool to sync the manipulated balance.
That breaks the reserve invariant, creates mispriced swaps, and keeps showing up across custom token integrations.
๐จ RWT Token - Loss ~$118K (2026-07-19)
Token: $RWT @ $0.00144
Network: BNB Chain
Type: Logic Error (deflationary burn-from-pair price manipulation + Flash Loan)
An unverified "sell" contract (0x8812) exposes an unprotected sell() that, each call, swaps RWTโUSDT into the RWT/USDT PancakePair, adds liquidity, then burns ~72M RWT directly out of the pair's reserves (RWT.burn is onlyOwner and the sell contract holds that role) and sync()s. Repeatedly burning the pool's RWT collapses its reserve and inflates RWT's USDT price, letting the caller extract USDT from the LP far above fair value. The attacker flash-loaned 1M USDT and looped the routine 18ร, draining the PancakePair (โ158.6K USDT / โ110M RWT) and netting ~118K USDT.
TX: https://t.co/Lg8B9xM9ka
Attacker: https://t.co/8LJDO0entY
Victim: https://t.co/xF6U9dONUX
โฑ๏ธ Real-time alerts: https://t.co/X9cKWDVOJz
๐จ Exploit Analysis
An AMM pair was drained because a privileged sell path could burn tokens directly from pool reserves, then force the pool to sync the manipulated balance.
That breaks the reserve invariant, creates mispriced swaps, and keeps showing up across custom token integrations.
You can see the exact failure point in the tx trace ๐
https://t.co/WcziPfWMiq
Notice how `sell(...)` leads into `burn(pair, amount)` and `sync()` across repeated cycles, turning a reserve mutation into overpriced RWT-to-USDT swaps.
๐จ @perpprotocol - Loss $3,062 (2026-07-16)
Token: $vETH (Perpetual Protocol)
Network: Optimism
Type: Access Control / Missing Permission Check
Perpetual Protocol's OrderBook exposes updateFundingGrowthAndLiquidityCoefficientInFundingPayment() as an unprotected external function (OrderBook.sol:232) โ it lacks the _requireOnlyClearingHouse() guard used by its sibling functions. The attacker opened a tiny liquidity order, then called it directly with a fabricated funding growth (twPremiumX96 = 1e70), corrupting their order's cached funding-growth state. On settleAllFunding the corrupted cache produced a bogus funding payment (~1.46e36), inflating the account's realized PnL, which was then withdrawn as USDC โ draining the vaults of ~$3,062.
TX: https://t.co/RCFvGsE4zB
Attacker: https://t.co/Xh3jEmS2Xp
Victim: https://t.co/4PIAloHs9C
โฑ๏ธ Real-time alerts: https://t.co/X9cKWDVOJz
๐จ Exploit Analysis
A perp-style OrderBook leaked its funding checkpoint update to arbitrary callers.
That let an attacker forge maker funding PnL, break accounting invariants, and drain 3,062.213107 USDC from two vaults.
This is not an isolated bug class: accounting writers are attack surfaces.