Blockchain security isn't optional.

Even seasoned protocols can fall to logic flaws. The Abracadabra hack proves that batching and state resets can bypass solvency checks. Don’t wait for an exploit, get your lending and router logic reviewed. Request a DeFi audit today.

Introduction to MIM Spell (Abracadabra.money)

Abracadabra.money is a decentralized lending platform that allows users to deposit interest-bearing tokens (ibTKNs) as collateral to borrow Magic Internet Money (MIM), a USD-pegged stablecoin. The recent abracadabra hack shows how composable systems that accept yield-bearing collateral can be exploited when batching and router logic contain subtle flaws. By accepting ibTKNs (such as yVault tokens) as collateral, the protocol enables users to unlock additional liquidity from yield-generating assets that would otherwise remain idle. This capital efficiency has made MIM Spell a core building block in the DeFi ecosystem, especially within our broader look at DeFi money markets, but also a complex one, where layered integrations and modular design leave room for subtle logic risks.

This is precisely why comprehensive smart contract audits from reputable firms remain fundamental, especially after incidents like the abracadabra hack, which highlight how batched transaction systems and complex collateral accounting can fail for protocols that rely on batched transaction systems, oracle-driven pricing, and collateral accounting across multiple markets.

The Third MIM Spell Incident (a short post-mortem on the abracadabra hack)

This marks the third major incident affecting MIM Spell, following two earlier exploits that collectively underscore the architectural risks of modular lending systems and the mechanics of decentralized borrowing.

While this latest event resulted in a ~$1.7 million loss, significantly smaller than the first (~$6.49M) and second (~$13M) incidents, it reveals another dimension of how state handling flaws in the Cauldron router can bypass solvency enforcement.

For context and continuity, we strongly recommend revisiting the previous breakdowns before diving into this one:

Together, these reports illustrate how small architectural oversights, such as improper debt accounting, deferred validation, or unchecked router extension logic, can lead to severe losses when combined with high-capital composability.

Under the Hood

Abracadabra operates through a modular system built on BentoBox technology, which provides the foundation for its non-custodial vaulting and lending mechanics:

  • DegenBox, a non-custodial vault that stores collateral and tracks token shares.
  • Cauldrons, isolated lending markets where users can borrow MIM against specific collateral types.
  • Yield strategies, optional integrations that earn returns on idle collateral within DegenBox.

Users deposit collateral into a Cauldron and borrow MIM based on a collateralization ratio determined by oracles. If collateral value drops below the liquidation threshold, liquidators can repay debt to seize collateral, maintaining solvency across markets.

This modular architecture is powerful but demanding: with multiple components interacting atomically, even a single flag mismanagement or unchecked hook can cascade through the system, as demonstrated by the sequence of MIM Spell exploits. For teams building cross-chain or routed liquidity, commissioning a blockchain bridge audit.

For those running similar deployments or analyzing EVM forks, security guidance can be found in our Solidity audits. Additionally, we at Three Sigma offer Rust/Solana audits, Move audits, and dApp frontend audits to address language and layer-specific vulnerabilities.

Architecture Overview (Where to find it)

For a detailed visualization of how Abracadabra’s components interact, Cauldrons, DegenBox, oracles, and liquidation paths, refer to the Architecture Overview included in our second exploit breakdown:

Draining the Cauldron: Inside the $13M Abracadabra GMX V2 ExploitDraining the Cauldron: Inside the $13M Abracadabra GMX V2 Exploit - Architecture Overview.

Attack Analysis

On October 4, 2025 at 12:54:23 PM UTC, an attacker exploited Abracadabra.Money’s Cauldron V4 contract to drain ~1,793,755 MIM (Magic Internet Money, worth about $1.79 million) in a single transaction (tx hash: 0x842aae91c89a9e5043e64af34f53dc66daf0f033ad8afbf35ef0c93f99a9e5e6). The exploit leveraged a flaw in the Cauldron cook() function that allowed bypassing the protocol’s final insolvency check. By bundling specific actions in one cook call, notably a borrow action followed by a rogue action ID 0, the attacker drew out an undercollateralized loan and avoided the solvent check that would normally prevent such unauthorized borrowing. The stolen MIM was then swapped through stablecoins and converted to Ether. In total, the attacker obtained ~395 ETH from the exploit, which was promptly withdrawn to external wallets and mixed via Tornado Cash to obfuscate the trail.

image

Vulnerability Exploitation

The exploit is rooted in a design flaw of the Cauldron V4 cook() implementation, which processes batched actions but fails to preserve critical state flags when an unexpected action is included. Below is a deep technical breakdown of how the attacker abused this flaw.

Misuse of cook() Function

Abracadabra’s cook() function lets users queue up multiple actions (like adding collateral, borrowing, repayments, etc.) to execute in sequence within one atomic transaction. Normally, if any of those actions could put the loan in danger of insolvency (e.g. borrowing or removing collateral), a flag needsSolvencyCheck is set, and a final check runs at the end to ensure the user remains solvent. The relevant code snippet (simplified for clarity) is shown below:

image

In the intended logic, ACTION_BORROW (ID 5) sets status.needsSolvencyCheck = true whenever a loan is taken (similarly removing collateral does the same). At the end of the loop, if this flag remains true, the contract invokes a solvency check to revert any transaction that left the user undercollateralized. However, the code also allowed for additional action IDs not defined in the base contract, via an _additionalCookAction hook in Cauldron V4, primarily to support extended features in special Cauldrons (e.g. GMX market actions). In the default implementation, any unrecognized action falls into the final else branch, which calls the stub _additionalCookAction and returns a default CookStatus(false, false), meaning no solvency check needed. This is the critical bug: the act of handling an unknown action resets the CookStatus struct, clearing the needsSolvencyCheck flag that was set by the prior borrow.

The attacker took advantage of this by crafting a cook call with an action sequence [5, 0], i.e. borrow then a dummy action 0.

image

Action 5 (ACTION_BORROW) successfully borrowed MIM to the attacker’s address and set the insolvency-check flag.

image

Then action 0, not a standard action, triggered the fallback logic, which wiped the CookStatus.

image

In the base CauldronV4 contract _additionalCookAction is defined but empty (no implementation).

image

Invoking an unimplemented virtual that returns (bytes, uint8, CookStatus) yields default zero values in Solidity:

  • returnData → bytes("")
  • returnValues → 0
  • returnStatus → CookStatus(false, false)

status becomes CookStatus(false, false) , overwriting both hasAccrued and needsSolvencyCheck to false.

After the loop the code checks:

image

Since status.needsSolvencyCheck == false (it was reset by the returned CookStatus), the require is not executed and the borrowed funds remain transferred out with no post-action solvency validation.

In other words, by the time cook() exited the loop, the contract believed no risky actions had occurred. Consequently, the final solvency check if (status.needsSolvencyCheck) was skipped entirely, and the protocol did not revert despite the loan leaving the account deeply insolvent.

Consequence: Bypass of Insolvency Checks

By resetting the internal CookStatus flags, the attacker bypassed Abracadabra’s core safety mechanism. Normally, the solvency check at the end of cook() would call the price oracle and run _isSolvent to ensure the borrower’s collateral value still exceeds their debt. If not, the transaction would revert with “Cauldron: user insolvent.” In this exploit, that check was never executed because status.needsSolvencyCheck remained false after the crafted action 0. The attacker effectively tricked the contract into thinking no borrow had occurred.

As a result, the attacker’s account was able to incur a large debt (nearly $300k MIM per attack wallet) with insufficient collateral, and no immediate liquidation or revert was triggered. The state was updated to record the new debt, the Cauldron’s userBorrowPart for the attacker increased and MIM stablecoins were minted to their address, but the usual invariant enforcement was absent. The screenshot below illustrates the state change: MIM tokens are transferred out from Abracadabra’s DegenBox (vault) to the attacker, with no error thrown.

image

Multiple Borrow Calls and Profit Extraction

The attacker repeated this cook([5,0]) trick across multiple wallets to maximize profit while evading per-address borrow limits. Six different attacker-controlled addresses each invoked the exploit, borrowing roughly 300,000 MIM per address (summing to ~1.8 million MIM total).

image

After draining the Cauldron contract of liquid funds, the attacker consolidated the stolen MIM and swapped them for more stable assets and eventually ETH:

  • Swap to USDC/ETH: Approximately 1.58 million MIM was swapped for ~1.58 million USDC, then traded for about 347 ETH (via decentralized exchanges).
  • Swap to USDT/ETH: Another ~215,000 MIM was swapped for ~215,000 USDT, then traded for about 48 ETH.

These swaps utilized aggregate DEX routes to minimize slippage, converting the stolen stablecoins into a total of ≈395 ETH. Finally, the attacker withdrew ~395 ETH to externally owned addresses. On-chain analysis shows the ETH was funneled into Tornado Cash shortly after, breaking the link between the funds and the exploit.

image
All six exploit transactions occurred in the same block timeframe. The Cauldron contracts were paused immediately after the team became aware of the issue

How the Attack Could Have Been Prevented

The Abracadabra CauldronV4 exploit stemmed from a logic flaw rather than a missing access control or oracle issue. Prevention would therefore have required robust internal consistency checks and safer design patterns for batching logic within cook(). Below are the key defensive strategies that could have prevented this incident.

1. Immutable needsSolvencyCheck Flag

A deep design-level fix would be to make the solvency check non-resettable within a single cook() execution.

The current implementation used:

image

which resets the struct entirely. Instead, updates should preserve previously set flags:

image

This way, once a borrow or collateral-removal action marks the transaction as risky, no subsequent operation can override that flag, even if additional actions return false.

2. Internal Solvency Validation per Action

While batching is convenient, it concentrates risk into a single post-execution check.

Introducing inline solvency checks after each borrow or collateral removal action (rather than deferring all to the end) would have eliminated the exploit path.

Example pattern:

image

This guarantees invariant enforcement regardless of subsequent actions, ensuring that no borrow can occur without immediate solvency validation.

However, this approach does come with trade-offs:

  • It reduces flexibility for legitimate complex user operations that depend on sequencing (e.g., borrowing and adding collateral within the same transaction).
  • It increases gas costs, since multiple solvency checks may trigger oracle reads and rate updates several times in one batched call.
  • It limits composability, as protocols relying on multi-step “atomic” position management may need to redesign their batching logic or implement conditional checks off-chain.

In practice, the ideal solution would balance security and flexibility, for example, enforcing inline solvency checks only on high-risk actions (borrow, withdraw, leverage), while allowing low-risk operations (repay, add collateral, accrue interest) to remain batched.

Additional Best Practices

  • **Rigorous Audits:** Any change that alters state ordering or accounting semantics (e.g., non-atomic sequences, “paper” collateral, deferred updates) should trigger deep accounting reviews focused on debt/collateral invariants and end-of-block state.
  • Invariant-Driven Testing: Add property/invariant tests (unit + integration) that assert:
    • “Borrow implies solvency check must occur,”
    • “Status flags cannot be cleared after risky actions,”
    • “Debt cannot increase without matching collateral constraints.”
  • Behavioral Fuzzing of Action Sequences: Fuzz over permutations of action arrays and edge cases (empty actions, duplicates, unknown IDs) to detect bypass of guards or inconsistent state transitions.

Consequences of the Abracadabra Hack

  • Direct financial loss: ~1,793,755 MIM (~$1.79M) was withdrawn from the protocol and converted into ETH/stablecoins, then partially moved off-protocol. This is the immediate, quantifiable loss to the protocol’s treasury/market liquidity.

The Protocol’s Response

  • Contracts paused: The protocol team has paused relevant Cauldron markets/contracts to prevent further borrowing and to contain additional loss.
  • No official public announcement on socials: As of the latest checks, there is no official statement posted on the protocol’s verified social media channels or website clarifying the incident, the scope, or next steps.
  • What is publicly visible on-chain: The exploit transactions, token flows, and subsequent swaps are observable on block explorers and forensic tools. The protocol’s pause state (on-chain) is visible where implemented.

Frequently Asked Questions (FAQ)

1) What is MIM and how does Abracadabra use it?

MIM (Magic Internet Money) is a stablecoin minted against over-collateralized positions inside Cauldron markets. Users deposit collateral, borrow MIM, and manage health based on exchange rates and protocol parameters.

2) Why was this latest incident significant?

A logic flaw in a batched-action router allowed an attacker to bypass a final solvency check, enabling under-collateralized borrowing and rapid extraction via swaps.

3) How can protocols reduce the risk of batching/routers?

Validate action IDs strictly, enforce per-action solvency checks on risk-bearing steps, and ensure flags like needsSolvencyCheck cannot be cleared later in the same batch.

4) Do language ecosystems matter for security?

Yes, each stack has unique pitfalls. Deep reviews like Solidity audits help catch EVM-specific sequencing bugs (e.g., batched routers, delegatecall patterns, precision loss).

5) What about non-EVM protocols?

Non-EVM chains have different memory, signer, and tx models. Targeted Rust/Solana audits focus on account model abuse, CPI boundaries, and rent/ownership checks that don’t exist on the EVM.

6) And Move-based chains?

Move’s resource semantics prevent some classes of bugs but introduce others (capabilities, module upgrades). Dedicated Move audits validate resource safety, access control, and upgrade scripts.

7) Frontend risks are real too, what should teams do?

Phishing and UX mis-signing can be as damaging as contract bugs. dApp frontend audits check wallet prompts, domain integrity, RPC/provider flows, and signing surfaces to reduce user-level compromise.

8) Where can I learn how to choose an auditor?

This overview helps non-security teams evaluate fit, scope, and methodology: What is a smart contract audit and how to choose the right security partner.

9) Are there patterns across recent DeFi incidents?

Yes, router misconfigurations, liquidation edge-cases, price-source assumptions, and unchecked “extension hooks” recur. See Top 2024 DeFi exploits & common vulnerabilities for a digest of patterns.

10) Where else can I read about past Abracadabra incidents?

Our two earlier breakdowns:

11) Which Cauldron was affected in this exploit?

The exploit targeted an older, low-liquidity CauldronV4 deployment, a market that had largely fallen out of active use at the time of the attack. This specific Cauldron was still live on-chain but had minimal TVL, which explains why the total loss amounted to ~$1.7 million, significantly lower than the prior $6.49M and $13M incidents.

Because the vulnerable contract remained publicly accessible yet inactive, it effectively acted as an unmonitored attack surface. Although the design flaw existed in the cook() implementation for months, the impact was limited only by the small collateral base still deposited in that legacy Cauldron.

12) How long had the vulnerability been live?

The vulnerable Cauldron contract was deployed on February 18, 2023, at 03:37:47 PM UTC. As of October 6, 2025, that means the contract had been live for 961 days, roughly 2 years and 7 months.

During this entire period, the flawed _additionalCookAction fallback logic remained in production, unnoticed and unpatched. Because this branch was rarely invoked in active markets, the issue stayed dormant until the attacker specifically targeted it in this legacy Cauldron deployment.

Reference: contract source / verified code, https://etherscan.io/address/0x692887E8877C6Dd31593cda44c382DB5b289B684#code

13) Why was the loss smaller compared to past incidents?

The smaller impact (~$1.7M) was primarily due to:

  • The low total value locked (TVL) in the affected Cauldron.
  • The isolation of markets, meaning only this specific Cauldron’s liquidity was at risk.
  • The quick pause of remaining Cauldrons once the exploit was detected.

While the architectural isolation prevented cascading effects, the existence of exploitable legacy deployments underscores why even inactive contracts should be formally deprecated and paused once superseded.

Simeon Cholakov
Simeon Cholakov

Security Researcher