Security
This page contains Arrow's audit history, security architecture considerations and attack attempt history.
Last updated
This page contains Arrow's audit history, security architecture considerations and attack attempt history.
Last updated
Security is a top priority for Arrow. Our smart contract architecture is stratified. Our hybrid architecutre avoids a P2Pool model which are the primary targets for DeFi attacks. However, we have a dedicated contract (UserFundsManager
) which acts as a middleman that facilities options transaction for buys and sell, transferring the funds from the buyer to the seller on purchase. There are multiple layers of redundancy ensuring the FundsManager
is secure.
Arrow contracts do not hold any user funds at any moment throughout any transaction.
User must approve a set amount of funds for the UserFundsManager
to be able to move the funds, which are then transferred directly between users and market makers.
It is important to never give unlimited approval to any contract including ours and only approve an amount you are willing to risk if the approval fund is not immediately used.
Background: Our FundsManager
contract uses a proxy-delegate structure for upgradeability, specifically the OpenZeppelin UUPS pattern. This means a shell "proxy" contract is deployed at an address that stays fixed for the lifecycle of the contract suite, and an implementation or "delegate" contract is deployed at a separate address that the proxy contract points to. Upgrades work by deploying a new delegate and updating the pointer address in the proxy. When an upgrade happens, an initialize function has to be called to set the contract router and other state variables. Initialize is only called once, and a boolean is set to True
to enforce that.
What Happened: During our last upgrade, we included new state variables, inadvertently moving the slot for the initialize boolean. The resulting slot had a value of 0. This allowed an attacker to call the initialize function and insert a malicious contract address in place of our Router. Subsequently, they were able to get around access modifiers in the FundsManager
by supplying their own Registry
contract address using their malicious Router
address. Finally, with this access, they deployed a malicious delegate contract and gained access to any funds that had been approved to the FundsManager
proxy, which was 277 USDC. We discovered this almost immediately and shut down the app and notified the affected parties.
Fix: We have deployed new FundsManager
proxies and implementations and rewired the frontend and Registry
` contracts accordingly. We have shored up our upgrade protocol to include a series of automated checks so the upgrade will fail if any state variables change location. We have also added access modifiers to the initialize functions. Drained funds were returned.
Diagnosis: This is not a weakness of the architecture per-se, but rather a weakness in our upgrade protocols which have now been shored up. We've had multiple audits and work closely with our auditor on an ongoing basis. Because of the modularized components and because it is p2p/p2MM rather than p2pool, Arrow's architecture is much harder to hack than conventional DeFi applications.