On Tuesday, 15th July 2025, Arcadia Finance was exploited on Base for $2.5 million USD1.
Exploiter: 0x0fa54E967a9CC5DF2af38BAbC376c91a29878615
via 0x6250DFD35ca9eee5Ea21b5837F6F21425BEe4553
Exploit Transaction:
0x06ce76eae6c12073df4aaf0b4231f951e4153a67f3abc1c1a547eb57d1218150
(trace)
Exploit Chain: Base (8453)
Exploited Codebase: arcadia-finance/asset-managers @ 723e7a9196a7953ecec95cd175abed0cedcb0936
Exploited Assets:
Audits: Pashov Audit Group
CVSS 3.1 Score: 9.3 (Critical)
CVSS 3.1 Vector: AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N/E:F/RL:O/RC:C/CR:X/IR:H/AR:X/MAV:N/MAC:L/MPR:N/MUI:N/MS:C/MC:N/MI:H/MA:N
SWCs: SWC-107
Rebalancer::executeAction
can only be called by the Rebalancer
contract; however, Rebalancer::rebalance
is world-callable (annotations added):
/**
* @notice Rebalances a UniswapV3 or Slipstream Liquidity Position, owned by an Arcadia Account.
* @param account_ The Arcadia Account owning the position.
* @param positionManager The contract address of the Position Manager.
* @param oldId The oldId of the Liquidity Position to rebalance.
* @param tickLower The new lower tick to rebalance to.
* @param tickUpper The new upper tick to rebalance to.
* @dev When tickLower and tickUpper are equal, ticks will be updated with same tick-spacing as current position
* and with a balanced, 50/50 ratio around current tick.
*/
function rebalance(
address account_,
address positionManager,
uint256 oldId,
int24 tickLower,
int24 tickUpper,
bytes calldata swapData
) external {
// If the initiator is set, account_ is an actual Arcadia Account.
if (account != address(0)) revert Reentered();
if (accountToInitiator[account_] != msg.sender) revert InitiatorNotValid();
// Store Account address, used to validate the caller of the executeAction() callback and serves as a reentrancy guard.
account = account_;
// Encode data for the flash-action.
bytes memory actionData =
ArcadiaLogic._encodeAction(positionManager, oldId, msg.sender, tickLower, tickUpper, swapData);
// Call flashAction() with this contract as actionTarget.
IAccount(account_).flashAction(address(this), actionData); // <---- arbitrary action data is submitted here in order to execute a flashloan
// Reset account.
account = address(0);
}
-- src/rebalancers/Rebalancer.sol:146-180
On line 176, a flashloan is processed via a call to IAccount::flashAction
, where arbitrary calldata is provided (actionData
). The IAccount
instance is instantiated on an arbitrary, attacker-controlled address (account_
). As such, once the call on line 176 is performed, Rebalancer
will jump into attacker-controlled code. Rebalancer::executeAction
can only be called by an IAccount
. Since the attacker has just established a way to perform calls from this IAccount
context, the attacker can now cause this method to execute.
By utilising the above dynamic, the attacker was able to arrange for a sequence of calls resembling the following:
Rebalancer::rebalance(attacker_controlled_calldata)
IAccount(acct1).flashAction(indirectly_attacker_controlled_calldata)
Rebalancer::executeAction(attacker_controlled_calldata)
IAccount(acct2).flashAction(directly_attacker_controlled_calldata)
In Step #4, the attacker has essentially gained control over IAccount(acct2)
. As IAccount::flashAction
is a trusted method, it accepts arbitrary debts and underlying assets and does not perform (economic) validation of them. Thus, the attacker can provide relatively smaller debt compared to the underlying assets and withdraw more than they are entitled to.
The actual exploit occurs in transaction 0x06ce76eae6c12073df4aaf0b4231f951e4153a67f3abc1c1a547eb57d1218150
. The attacker uses an exploit smart contract (0x6250DFD35ca9eee5Ea21b5837F6F21425BEe4553
) to manage ERC20 token approvals, flashloan via Morpho, and then reenter into Arcadia's RebalancerSpot
.
Time | Event |
---|---|
2025-07-14T11:29:17+00:00 | Attacker EOA is initially funded in transaction 0xc41c5ee09f8e452c253040a4e1cd942d5bc373597fca9da77303bc91da7be2e7 |
2025-07-15T04:05:45+00:00 | Attacker EOA executes exploit in transaction 0x06ce76eae6c12073df4aaf0b4231f951e4153a67f3abc1c1a547eb57d1218150 |
2025-07-15T17:28:00+10:00 | Chaofan Shou of Fuzzland posts the first analysis on X/Twitter |
2025-07-15T17:44:00+10:00 | Cointelegraph reported the hack on their news service |
[1] C. Shou, “The @ArcadiaFi hack,” X (formerly Twitter), Jul. 15 2025. [Online]. Available: https://x.com/shoucccc/status/1945022619063144856/photo/1. [Accessed: Jul. 15, 2025].
[2] Arcadia Finance, “Official team announcement,” X (formerly Twitter), Jul. 15, 2025. [Online]. Available: https://x.com/ArcadiaFi/status/1944984622183370867. [Accessed: Jul. 15, 2025].
[3] A. Manning, “Solidity Security: Comprehensive list with known pitfalls, best practices, real world attacks and potential code snippets,” Sigma Prime Blog, May 30, 2018. [Online]. Available: https://blog.sigmaprime.io/solidity-security.html. [Accessed: Jul. 15, 2025].
[4] A. Haqshanas, “Arcadia Finance exploited, $2.5M stolen and converted to WETH,” Cointelegraph, Jul 15, 2025. [Online]. Available: https://cointelegraph.com/news/arcadia-finance-exploit-2-5m-crypto-theft. [Accessed: Jul. 15, 2025].
Approximate fair market value as at the time of occurrence.