Impermax Hack Analysis
Impermax Hack Analysis
Overview:
On October 4, 2025, Abracadabra Money (@MIM_Spell), a decentralized lending platform on Ethereum that issues USD-pegged MIM (Magic Internet Money) loans, suffered a critical solvency bypass exploit via the cook() multi-action entrypoint., resulting in an estimated loss of ~$1.7 million USD. This protocol has been attacked for the third time in past 2 years; with heavy losses every time ($13.5M in January 2024, $6.5M in March 2024, and now ~$1.7M in October 2025).
The vulnerability was located in the cook() function of the PrivilegedCauldronV4 and PrivilegedCheckpointCauldronV4 contracts, where an uninitialized “else” branch unintentionally reset internal status flags, disabling collateral checks during borrow operations.
This flaw allowed the attacker to borrow MIM without any collateral, performing the attack across six Cauldron instances and draining approximately 1,724,494 MIM, which was later swapped into ~395 ETH in profits.
Smart Contract Hack Overview:
- Attack Transaction:
0x842aa - Victim Contracts (Cauldron instances):
0x46f54,0x28942,0xce450,0x40d95,0x6bcd9,0xC6D3b - Attacker Address:
0x1AaaDe - Attack Contract:
0xB8e0A(Self-Destructed) - OWASP SC Top 10: SC03:2025 Logic Errors
Press enter or click to view image in full size

Fig: Attack Transaction
Decoding the Smart Contract Vulnerability:
- The root cause of the exploit lies in the
cook()function, which is the core batching mechanism in Abracadabra’s CauldronV4 contracts. This function is designed to let users chain multiple operations such as deposits, borrows, and repayments into a single atomic transaction.
Press enter or click to view image in full size

Fig: Vulnerable cook() Function
- The
cook()function processes an array of encoded actions, executing them sequentially in a loop. Each action (represented by an integer code (e.g.,ACTION_BORROW = 5) and associated encoded parameters (datas[])) modifies a temporary execution context calledCookStatus, which tracks key control flags such as whether a solvency check must be performed at the end. To track transient control flags during this batch, the function uses a local struct:
struct CookStatus {
bool needsSolvencyCheck;// Indicates if solvency must be verified at the end
bool hasAccrued; // Tracks whether interest has been accrued
}
- Each action can modify
CookStatus. For instance:
if (action == ACTION_BORROW) {
(value1, value2) = _borrow(to, _num(amount, value1, value2));
status.needsSolvencyCheck = true;
}
- This ensures that any borrow or collateral removal triggers a final solvency validation.
Press enter or click to view image in full size

Fig: Vulnerable _additionalCookAction()
- So, here the vulnerability arises from _additionalCookAction(), designed to allow extended, undefined or custom actions like (action = 0):
function _additionalCookAction(
uint8 action,
CookStatus memory,
uint256 value,
bytes memory data,
uint256 value1,
uint256 value2
) internal virtual returns (bytes memory, uint8, CookStatus memory) {}
- For any unknown action IDs (action = 0),
cook()delegates execution to_additionalCookAction(). In the V4 implementation,_additionalCookAction()returns a default-initializedCookStatus, effectively resettingneedsSolvencyChecktofalse. This means any prior borrow or collateral removal flag is silently cleared, allowing the final solvency check incook()to be bypassed:
status = returnStatus; // returnStatus has needsSolvencyCheck = false
...
if (status.needsSolvencyCheck) {
(, uint256 _exchangeRate) = updateExchangeRate();
require(_isSolvent(msg.sender, _exchangeRate), "Cauldron: user insolvent");
}
- As a result, the attacker borrowed ~1.7M MIM without sufficient collateral, exploiting the fact that the batching mechanism’s transient control flags were improperly preserved across custom actions.
- The attacker got away with about 1,724,494 MIM- roughly $1.7 million USD at the time of the incident. Those MIM were successively swapped to ETH, yielding approximately 395 ETH in net proceeds before the attacker self-destructed the exploit contract.
- Abracadabra Team acknowledged the incident via their official X account: https://x.com/MIM_Spell/status/1975130787486831018

Fig: Official Status from Abracadabra Money Team
- The Abracadabra Team also stated that during the incident, no user funds were lost, and the effect has now been already full mitigated.
Attack Sequence:
The attacker funded their exploit contract using Tornado Cash to obfuscate the source of funds.
Then, they called the
cook()function on multiple CauldronV4 contracts, passingactions = [5, 0]to trigger the exploit.
The
ACTION_BORROW (5)executed a borrow operation, which set theneedsSolvencyCheckflag totrue.
And, the
ACTION_0then called the empty_additionalCookAction()function, which reset theneedsSolvencyCheckflag tofalse.
As a result, the final solvency check in
cook()was skipped, allowing the attacker to bypass collateral verification.
Thus, the attacker successfully kept the borrowed MIM without providing any collateral.
They repeated this sequence across six different CauldronV4 contracts to maximize the stolen amount.
Then, attacker then swapped the stolen MIM through a series of conversions: MIM → DAI → USDC → WETH → ETH.
Finally, the exploit contract self-destructed, transferring approximately 395 ETH in profit to the attacker’s wallet.
Press enter or click to view image in full size

Fig: Attack Sequence Visualized
Mitigation and Best Practices:
- Avoid relying on transient state across actions. Never assume that a local struct or flag will persist safely through multiple actions. Always design control flags to be immutable or explicitly validated at critical checkpoints.
- When extension hooks return status structs, merge boolean flags (e.g.,
needsSolvencyCheck ||= returnStatus.needsSolvencyCheck) instead of doingstatus = returnStatus. This prevents later/unknown actions from clearing security-critical flags. - Replace silent fall-throughs with an explicit
revert("Unknown cook action")for unsupported action codes, or make the default hook explicitlyrevert()unless intentionally overridden. Never allow a no-op default that can reset state. - Any custom or undefined actions (like
ACTION_CUSTOM) should either be disabled or strictly validated to prevent unintended side effects, especially in multi-action batch functions. - Use fuzzing, symbolic execution, and formal verification tools to test all possible action sequences, ensuring no combination can bypass security-critical checks.
- To prevent such vulnerabilities, the best Smart Contract auditors must examine the Smart Contracts for logical issues. We at CredShields provide smart contract security and end-to-end security of web applications and externally exposed networks. Our public audit reports can be found on https://github.com/Credshields/audit-reports. Schedule a call at https://credshields.com/
- Scan your Solidity contracts against the latest common security vulnerabilities with 494+ detections at SolidityScan.

Fig: SolidityScan — Smart Contract Vulnerability Scanner
Conclusion:
SolidityScan is an advanced smart contract scanning tool that discovers vulnerabilities and reduces risks in code. Request a security audit with us, and we will help you secure your smart contracts. Signup for a free trial at https://solidityscan.com/signup
Follow us on our Social Media for Web3 security-related updates.