Mar 29, 2024
Summary
A vulnerability in both versions of the
MigrateTroveZap
(mkUSD and ULTRA) contract of Prisma Finance led to a loss of 3,479.24 ETH, or approximately $12 million USD.In response, the Prisma Finance emergency multi-sig has paused the protocol's operations.
The vulnerable contract is a special-purpose contract designed to migrate user positions from one trove manager to another.
The vulnerability affects Prisma Trove owners who approved this contract to manage their Trove's position via
setDelegateApproval(MigrateTroveZap, True)
on theBorrowerOperations
contract.The issue occurred when an exploiter made a transaction that, with a lack of input validation in the
onFlashloan
function, allowed the exploiter to manipulate the contract's behavior and take a portion of a Trove owner's collateral.As a result, the exploiter was able to close a Trove owners Trove, withdraw the collateral (wstETH), and reopen the Trove with the same debt (mkUSD) but less collateral, taking the difference.
A thorough investigation is conducted to identify the root cause and implement necessary fixes.
There was a primary exploiter (Exploiter 1) followed by copycat exploiters.
Trove owners should verify they have revoked any active approvals for the
MigrateTroveZap
.
Background
Prisma Finance deployed a contract called MigrateTroveZap
to facilitate trove owners migrating their Troves (collateralized debt positions) to new TroveManager contracts. This was part of a broader system upgrade announced in March 2024.
As part of these updates, Prisma deprecated the original 4 LST (Liquid Staking Token) Vaults with a 4% interest rate cap, replacing them with new LST Vaults, allowing for higher rates. The 3 LRT (Liquid Restaking Token) Vaults were also deprecated and replaced with new versions optimized for more efficient redemptions.
Prisma built the MigrateTroveZap
helper contract to ensure a smooth transition, enabling trove owners to seamlessly move their Trove positions from the old TroveManager
contracts to the new ones without needing to close positions, remove liquidity, or incur additional costs. The contract uses flash loans to close the user's old Trove and immediately open a new Trove with the same collateral and debt in the new TroveManager
, all in one atomic transaction.
These changes followed Prisma's standard DAO governance process, with the migration starting with the deployment of the MigrateTroveZap
contract on March 20th, 2024, and the first trove owners migrating Troves using the helper contract from March 23rd onwards.
Details of the Incident
On March 28th, 2024, at 11:25 UTC, an exploiter (Exploiter 1](https://etherscan.io/address/0x7e39e3b3ff7adef2613d5cc49558eab74b9a4202)) made a transaction in the MigrateTroveZap
contract, resulting in a total transfer of around 3,257 ETH (approximately $11 million USD) from some Prisma Finance Trove owners. This was followed by two other exploiters (Exploiter 2 and Exploiter 3) that managed to transfer a smaller amount of ~121 and ~52 wstETH, respectively. The incident was made possible due to insufficient input validation in the onFlashloan()
function, which allowed the Users to manipulate input data and execute unintended contract behavior.
Affected Trove owners had previously migrated from TroveManager
v1 to v2 using the migration contract. This involved setting delegate approval in the BorrowerOperations
contract with MigrateTroveZap
as an argument. Although the vulnerability affects both the MigrateTroveZap
contract for mkUSD and ULTRA and all TroveManagers
, only the wstETH Troves for mkUSD were targeted.
The Prisma team has advised Trove owners to revoke delegate approval and announced a convenient process to do so on the Prisma app. The team has also paused the protocol, disallowing new collateral to be added and blocking further damage. Once unpaused, any open zap approvals are still open to this issue.
Detailed timeline (March 28th)
11:15 UTC: Exploiter 1 wallet is funded via FixedFloat exchange
11:22 UTC: Exploiter 1 Exploit contract is deployed
11:25 UTC: Exploiter 1 calls function
0x82be0b96
, initiating the transaction.11:29 UTC: The Prisma Team is alerted by a community member on Discord.
11:51 UTC Prisma announces a potential incident on Twitter.
12:11 UTC: Prisma advises users to revoke delegate approval on both LST and LRT
BorrowerOperations
12:41 UTC: Exploiter 2 executes its first transaction.
12:49 UTC: Exploiter 3 executes its first transaction.
12:51 UTC: Emergency multi-sig calls
Paused()
General Logic
The exploiters took advantage of the vulnerability through the following steps:
The exploiters bypassed the migrate function and called the flash loan directly with carefully crafted input data.
The flash loan's callback function,
onFlashloan()
, was called.The lack of proper checks allowed the exploiters to close a Trove owner's Trove and immediately reopen it within the same
TroveManager
. The transaction caused the owner's position to be closed and reopened, resulting in the Trove owner having a new position with the same debt but less collateral and the difference in collateral sitting in the zap contract.The exploiters then opened a new Trove and used the
MigrateTroveZap
contract to migrate it, effectively using the remaining collateral for their own Trove.Finally, the exploiters closed their Trove and took the profits.
Example Tx
The incident was conducted in a series of transactions that targeted vulnerable Troves individually. The diagram shown below is a simplified funds flow of the first transaction, whereby the wstEthTroveManagerV2
(0x1cc) sends a victim's collateral to MigrateTroveZap
, sends it back to wstEthTroveManagerV2
, and finally sends the amount to the Contract (0xd99).
Source: Phalcon
The exploiter closed the active Trove of the TroveOwner, which had a Trove open with 1745.08 wstETH collateral and 1,442,100 mkUSD debt. The Trove owner's Trove was immediately reopened with 463.18 wstETH collateral and 1,443,398 mkUSD debt. This reduced the collateral ratio from around 498% to 132%, putting it at risk of liquidation.
Source: Phalcon
The exploiter proceeded to open a small Trove with one wstETH collateral and 2,000 mkUSD debt. They migrated the position using MigrateTroveZap
and reopened a Trove that inherits the remainder of the wstETH in the contract. The reopened Trove had 1,282.79 wstETH collateral and 2,001.8 mkUSD debt.
Source: Phalcon
Finally, the exploiter closed the Trove, receiving 1,282.79 wstETH, and paid back all necessary flash loans to Balancer and Prisma.
Source: Phalcon
The root cause of the vulnerability was twofold:
By directly calling the flashloan() function, the exploiter could manipulate other Trove Managers' positions.
The contract allowed for a mismatch between the collateral in the initial position and the collateral in the new position, with the difference being susceptible to being taken.
Flashloan function of MigrateTroveZap
- Source: ContractReader.io
Consequences of the protocol being paused
Pausing in Prisma is a security mechanism that halts certain operations during emergencies or unforeseen issues. When paused, functions like opening new vaults, increasing collateral or debt, and depositing into Stability Pools are disabled. However, users can still withdraw collateral to minimize the risk of locked funds. In the incident's context, pausing likely prevented further incidents by disabling new Troves and collateral addition.
Key Addresses
Exploiter 1 (EOA)
0x7E39E3B3ff7ADef2613d5Cc49558EAB74B9a4202
Exploiter 2 (EOA)
0x7Fe83f45e0f53651b3ED9650d2a2C67D8855e385
Exploiter 3 (EOA)
0x7C9FC6E2B908e858F30c5c71a20273315Efd5cf8
Exploiter 1 contract
0xd996073019c74b2fb94ead236e32032405bc027c
Exploiter 2 Contract
0x4148310fe4544e82f176570C6c7B649290a90E17
Exploiter 3 Contract
0x1b8A9F9F5a1d9cB1C28D9120F9c2bD073ccfAC04
MigrationTroveZap (mkUSD)
0xcC7218100da61441905e0c327749972e3CBee9EE
MigrationTroveZap (ULTRA)
0xC3eAf094e2586965244aB6534f6Dc69c6C16b5D5
mkUSD Contract
0x4591dbff62656e7859afe5e45f6f47d3669fbb28
New wstETH TroveManager
0x1cc79f3f47bfc060b6f761fcd1afc6d399a968b6
Borrower Operations (LST)
0x72c590349535AD52e6953744cb2A36B409542719
Prisma Emergency msig
0x7A28A80DcE1733944Db5dC50dc2c5147eC993C5A
Incident proceeds
Exploiter 1 Funds Recipient
0x2d413803a6eC3Cb1ed1a93BF90608f63b157507a
757.69 ETH LINK0x57f7033F84894770F876bf64772E7EBA48990D65
1,500 ETH LINK0x5d0064f3B54C8899Ab797445551058Be460C03C6
1,000 ETH LINK
Exploiter 2 Funds Recipient
0x7fe83f45e0f53651b3ed9650d2a2c67d8855e385
138.19 ETH LINK
Exploiter 3 Funds Recipient
0x7C9FC6E2B908e858F30c5c71a20273315Efd5cf8
52.32 wstETH LINK
Affected wallets
Exploiter 1 | Count: 11
Exploiter 2 | Count: 11
Exploiter 3 | Count: 3
Actions Needed
Users with open Vaults should head over to the Revoke Approval page and follow the instructions there.
Next Steps
The Prisma team along with many others are continuing the investigation and working to communicate with the Exploiters.
While retrieving all Trove owners funds is our main focus right now, unpausing the protocol will be part of the next steps once we are sure that all positions are safe.
Further steps will be published once a plan is worked out.
Acknowledgments
Thanks to Dan from HyperNative Labs, who was the first one to directly reach out to us.
We extend our gratitude to Llama Risk and Wavey for their invaluable assistance in compiling information and crafting this report. Their dedication and expertise significantly enhanced the quality and depth of our analysis.
We are immensely thankful to our friends and contributors who joined us in the War Room, offering their unwavering support and insights from the inception of our response. Their collaboration and swift action were instrumental in navigating through these challenges.
We are glad to be counting on the support and expertise of MixBytes, our historical security partner.
Special recognition goes to ZachXBT for his in-depth assistance. His observations proved indispensable in addressing the issue promptly and decisively.
Thanks to everyone who reached out to offer help and assistance. The solidarity from the space that we felt was an incredible support and will help face the next challenges.