Post Mortem

Arcadia Finance
4 min readJul 10, 2023

--

Overview

In the morning of July 10th 2023, the Arcadia Finance team became aware of an exploit in the lending part of its protocol. The loss of the protocol was ~$460k.

In order to mitigate the risks of further funds being exploited, the Arcadia team proceeded to pause the protocol. As of this writing, no other assets were impacted.

The attack was performed by 0xD3641C912a6A4c30338787E3C464420b561A9467 on Optimism and 0x5C75e94dD0Ab9c10BFd1B8073DafEF031D3c050d on Ethereum.

Our highest priority remains the recovery of lost funds, and we continue to work closely with law enforcement and security experts to identify the hacker and recover all misappropriated funds.

A first post-mortem of the exploits follows in this post. More detailed posts will follow over the course of the next days.

Exploit transaction on optimism:

https://optimistic.etherscan.io/tx/0xca7c1a0fde444e1a68a8c2b8ae3fb76ec384d1f7ae9a50d26f8bfdd37c7a0afe

Exploit transaction on mainnet: https://etherscan.io/tx/0xefc4ac015069fdf9946997be0459db44c0491221159220be782454c32ec2d651

Exploit

  • The exploiter took a flash loan of 2.4 WETH and 20,672 USDC.
  • The exploiter drained the WETH liquidity pool.
  • The exploiter drained the USDC liquidity pool.
  • The exploiter repays the flash loan.

For each pool, the attacker repeated a few steps; the following example is the USDC pool:

  • First, the exploiter creates a new Vault. A Vault is a user-owned contract that holds collateral assets and against which funds are borrowed from the Liquidity Pool.
  • The exploiter deposits the 20,672 USDC.
  • The exploiter calls doActionWithLeverage() (the function allows a user to borrow capital in a flash-loan manner, where the condition they need to meet is that the position/vault should be healthy at the end), this allows the exploiter to borrow 103,210 USDC from the Liquidity pool and deposits the borrowed funds immediately back into the Vault → assets in vault: 123,882 USD, debt: 103,210 USDC.
  • The exploiter deploys his attack contract.
  • The exploit: the attacker calls vaultManagementAction(), the function with the vulnerability, discussed in detail next.

The function vaultManagementAction() lets a vault owner manage (swap, stake, unstake…) the assets optimistically.

Users can

  • Withdraw assets to a multi-call contract.
  • Interact with third-party contracts with the withdrawn assets via the multi-call contract.
  • Deposit allow listed recipient tokens back in the vault.

Only after all user interactions, a health check (assets > liabilities) is performed.

The root cause of the exploit is a missing reentrancy check upon liquidation of a Vault. During the multi-call, the Vault is reentered indirectly via LendingPool → Liquidator → Vault:

  • First, the attacker withdraws all assets from the Vault. → assets in the vault: 0 USD, debt: 103,210 USDC.
  • In the multi-call the attacker calls liquidateVault() on the LendingPool (this is the reentrancy that should have been blocked)
  • Since we optimistically withdrew the assets, the vault now holds 0 assets but still has debt → liquidation is successfully initiated.
  • After a successful liquidation, an auction is started, and the debt is removed from the vault. → assets in the vault: 0 USDC, debt: 0 USDC

Due to this reentrancy via the Liquidator, the vault now has 0 assets and 0 debt, and the final health check of vaultManagementAction() passes.

Unlike the information that has spread since this morning, the core issue is not the lack of validation of untrusted input.

Some snippets of the most important functions and contracts are shown below:

Function liquidateVault() on contract Vault:

Function liquidateVault() on contract LendingPool:

Function liquidateVault() on contract Vault, called by Liquidator during a liquidation:

Short-term mitigation

Contracts related to Arcadia liquidity pools have been paused. No additional debt can be taken or repaid. The interest rate has been set to 0 to prevent any accumulation of interests.

A fix for this is in the works and will be audited shortly. A reentrancy guard on the Vault (especially the liquidateVault() function) when vaultManagementAction() is added.

Summary of the financial impact

broken down per chain and per asset:

Ethereum

  • USDC: 103,200.653468 → $103,200.65 USD
  • Ether: 11.047195997555799542 → $20,558.72 USD

Optimism

  • USDC: 59,427.425162 → $59,427.42 USD
  • Ether: 148.224144212923406305 → $275,843.65 USD

Total: $459,030.44 USD

Aftermath

The team reached out to both attacker addresses. As of now, there has yet to be a response.

https://optimistic.etherscan.io/tx/0xc598bf554a738ebeec234930e4bffe1c7a4266a1bbbdfae63b6951e448a17fc5

https://etherscan.io/tx/0x01e2683bfdb945fcb6af7ed6a656dbabb04d7c8135125184fd29f5665fd0546c

We have been working closely with a security team, including BlockSec, Hexagate, Peckshield, and many other experts specializing in on-chain analysis and off-chain opsec alongside international law enforcement. Besides obtaining addresses linked to centralized exchanges, we also uncovered links to previous exploits of other protocols. The team is investigating both on-chain and off-chain data to the fullest extent and has multiple leads. Our highest priority remains the recovery of lost funds

We are closely working with local and international law enforcement agencies to do what’s necessary, all with the goal of recovering the lost funds. To the extent possible, we will keep you updated on new developments.

Should any more info become available, we will inform our community and users.

--

--