HACK ANALYSIS 7 min read

Arcadia Finance Hack Analysis


Arcadia Finance Hack Analysis

Overview:

On July 15, 2025, Arcadia Finance (@ArcadiaFi)— a liquidity and asset management protocol — was exploited for nearly $3.5 million on Base. The attacker leveraged a critical trust assumption flaw in the RebalancerSpot contract. Specifically, a swapData parameter allowed arbitrary external calls to unvalidated router addresses.

By registering their own malicious smart contract as both the router and a whitelisted ArcadiaAccount, the attacker spoofed privileged execution contexts and hijacked control flow. This allowed unauthorized withdrawals from other user accounts via manipulated rebalance flows.

The root issue lies in the assumption that the router address passed via swapData would not be a contract with elevated permissions — which was not enforced in code. Once triggered, the attacker repaid debts of a target account to meet health checks, used the Rebalancer to invoke a custom malicious call, and drained LP tokens from the victim’s position.

This vulnerability is an example of OWASP SC06:2025 Unchecked External Calls.

Smart Contract Hack Overview:

On Base:

Fig: Attack Transaction

Decoding the Smart Contract Vulnerability:

  • The root cause of the Arcadia Finance exploit lies in the lack of validation in the SwapLogic._swapViaRouter() function. This allowed an attacker to inject a malicious router via the router.call(data) mechanism, leveraging the trusted context of the Rebalancer contract (msg.sender) to perform unauthorized actions on victim accounts.
  • The exploit path traverses multiple contracts: RebalancerSpot.sol, Rebalancer.sol, and SwapLogic.sol.
Fig: rebalance() function in Rebalancer.sol
  • In the Rebalancer.sol contract, the rebalance() function is externally callable and enables anyone to initiate a rebalance operation if they are registered as the initiator. The attacker first registers as a valid initiator and then calls rebalance() with carefully crafted swapData. This data encodes a malicious router address and a payload (data) that performs unauthorized operations.
Fig: Rebalancer.executeAction() function
  • During the rebalance process, the Rebalancer contract calls flashAction() on the user-supplied ArcadiaAccount, designating itself (address(this)) as the callback. This causes the ArcadiaAccount to invoke the executeAction() function on the Rebalancer, completing the flash execution flow.
Fig: _swap() in Rebalancer.executeAction()
  • Inside Rebalancer.executeAction(), the swap logic is delegated to SwapLogic._swap(), which further calls _swapViaRouter(). Here lies the critical flaw.
  • The _swapViaRouter() function performs two key actions: 
    1. Approves the exact amountIn of the input token to the attacker-controlled router via safeApproveWithRetry().
    2. Executes an arbitrary low-level call to the router via:
(bool success, bytes memory result) = router.call(data);
Fig: Vulnerable _swapViaRouter() in SwapLogic.sol
  • Because this low-level call is performed from within the Rebalancer contract, the called contract (i.e., the malicious router) sees msg.sender == Rebalancer.
  • In Arcadia’s architecture, ArcadiaAccount contracts maintain a list of authorized AssetManager addresses — typically including the Rebalancer. Therefore, if a contract is called from the Rebalancer’s context, it can inherit those elevated privileges.
  • The attacker exploited this by designing a malicious router contract that, when called, triggered sensitive functions on a different ArcadiaAccount (the victim’s). Because the Rebalancer was already whitelisted in that victim account, and because the account was in a “healthy” state (no outstanding debt), the call succeeded. The withdrawal executed as if it were from a trusted manager.
  • This resulted in the unauthorized draining of liquidity provider (LP) tokens from user accounts. The Rebalancer approved the malicious contract for token transfers, and the malicious contract called sensitive functions with elevated context — effectively bypassing all access control.
  • The total loss amounted to approximately $3.5 million across LP positions, all stemming from this unchecked assumption: that the router supplied in swapData would always point to a safe, external DEX (like Uniswap or 1inch).
  • The exploiter then swapped the stolen funds for ~840 $ ETH & bridged them from Base to Ethereum. Currently, the stolen fund is parked at: 
    https://basescan.org/address/0x0fa54e967a9cc5df2af38babc376c91a29878615 (~3.6M USD)
Fig: Attack Call Sequence
Fig: Arcadia’s acknowledgement on X

Attack Sequence:

Attacker creates multiple Arcadia Accounts and takes ~$1.5B flashloan from Morpho Blue to fund the exploit.

Then, links Asset Manager to their own Arcadia Account, setting self as initiator. And creates a small LP position to trigger the rebalance flow.

Fully repays the debt of a victim Arcadia Account using the flashloan — bringing it to a “healthy” state.

Calls rebalance() on their own account, injecting malicious swapData.

Inside SwapLogic._swapViaRouter(), the attacker’s malicious contract is called via router.call(data).

That malicious contract executes arbitrary calls to the victim Arcadia Account (e.g., calling sensitive functions). These calls succeed because: 
1. The Rebalancer is already whitelisted in the victim account. 
2. The account is healthy (no active debt), so failsafes are bypassed.

Victim’s funds are transferred out to the attacker.

And the flashloan is repaid using part of the stolen funds.

Attacker now retains the remaining stolen assets.

Fig: Attack Sequence Visualized

Detection by SolidityScan:

  • SolidityScan was able to detect the exact vulnerable line in Arcadia Finance’s RebalancerSpot (Base) contract that led to a $3.5M exploit .
  • Scanning the contract early on with SolidityScan would have flagged this critical vulnerability. This single scan could have saved Arcadia Finance over $3.5M USD and protected user funds.
Fig: Solidityscan was able to catch the vulnerability!
Fig: Simple steps to scan any contract on SolidityScan!
  • Don’t wait for a hack postmortem to learn from — catch critical bugs before they go live.
  • Integrate SolidityScan into your development CI/CD pipeline and secure every deploy!

Mitigation and Best Practices:

  • Ensure that only trusted DEX contracts (e.g., Uniswap, 1inch) can be passed as routers in swapData. Maintain an allowlist of approved router addresses.
  • Also, do not rely solely on msg.sender for access control in contexts involving delegate calls or external router calls. Add explicit checks on the origin of privileged actions.
  • Before executing arbitrary low-level call()s (like in _swapViaRouter()), verify that the target contract cannot execute unintended privileged logic.
  • Before performing privileged actions like withdrawals, verify that the action is appropriate for the account’s state (e.g., debt must be active, initiator must be whitelisted, etc.).
  • Carefully audit any flow that uses flashloans or allows callbacks — especially if it allows arbitrary calldata injection — since these can introduce hidden reentrancy and privilege escalation vectors.
  • 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.

SolidityScan — LinkedIn | Twitter | Telegram | Discord