# The CPIMP Backdoor, the USPD Incident and how the UI/UX is tricking us ## 0. Introduction Back in Defi Security Summit, a couple weeks ago, an exploit that has been around for some time was disclosed by [Yannis](https://x.com/YSmaragdakis), (Dedaub Co-Founder). This exploit is known as **[CPIMP](https://www.youtube.com/watch?v=RShnWs0V120)**, and had already (partially) affected many teams such as EtherFi, Kinto Finance, Berachain, Pendle... Here I’ll walk through the insights and analysis that [Gianfranco](https://x.com/0xGianfranco) and I discussed after getting nerd-sniped by the USPD incident. *Note: The video is a must watch regarding the creativity of an attacker* ## 1. What happened? USPD and the CPIMP Attack: The 4th of December 2025, the USPD team disclosed an [incident](https://x.com/USPD_io/status/1996711283446464598): - An attacker managed to take control of a core upgradeable proxy during the **deployment window**, i.e. between proxy deployment and its correct initialization. - That control was used to install a malicious intermediate proxy, a **CPIMP**, between the protocol proxy and the implementation that had been audited. - After some time with the system apparently behaving normally, the attacker executed the final step of the attack: minting tens of millions of USPD and draining staked collateral (e.g. stETH). ![{E46C74C3-8D7B-47DB-824B-BD7EE61D59E3}](https://hackmd.io/_uploads/B1UB9ibGWl.png) ## 2. How CPIMP is tricking you ![{A4E7ADAF-5C37-47B0-9219-DEC92DDCE92E}](https://hackmd.io/_uploads/ByX38hZzWx.png) CPIMP is based on a simple idea: > Instead of attacking the protocol logic directly, place a proxy controlled > by the attacker **in the middle**, so that everything looks normal but every > call flows through the attacker-controlled piece first. Formally, CPIMP (*Clandestine Proxy In the Middle of Proxy*) proceeds as: 1. Identify a freshly deployed, **uninitialized** proxy. 2. Call `initialize` **before** the team does, setting the proxy's implementation to a contract controlled by the attacker: the **CPIMP**. 3. The CPIMP stores internally the address of the “legitimate” implementation the team intended to use. 4. From that point on, the call graph changes from: ```text Proxy --> Implementation ``` to: ```text Proxy --> CPIMP --> Implementation ``` To make this a practical backdoor, the attacker adds two properties: * **Camouflage**: * The CPIMP forwards normal calls without visible changes. * It can emit events and manipulate specific storage slots so that explorers (Etherscan, etc.) display the legitimate implementation to users. * **Persistence**: * At the end of each update transaction, the CPIMP re-installs itself into the implementation slot (typically the EIP-1967 slot). * That way, even if the team performs upgrades, the first `delegatecall` still hits the CPIMP. Result: * From the outside, everything looks normal. * Explorers see the expected implementation. * Functional tests pass. * But there is a “man in the middle” that can change the rules whenever the attacker decides. ## 3. How Block Explorers UI/UX can mislead you An important aspect of the USPD incident is not just what happened on-chain, but **how the attacker leveraged explorer UX to mislead the developers**. At the root of the problem we have an operational mistake: - The deployment of the upgradeable proxy and its initialization were **not** atomic - The proxy was deployed using an `upgradeToAndCall` style flow where the initialization `data` was `""` (empty). - That empty initialization payload meant the proxy was left effectively uninitialized, leaving a window during which *any* account could run the first valid `initialize` and take control. Concretely: - The proxy was deployed at block **23375794**. - If you look at Etherscan in the **default** [view](https://etherscan.io/txs?a=0x1346b4d6867a382b02b19a8d131d9b96b18585f2&p=2), the first transaction shown as “to” the proxy contract is the **legitimate** [initialization](https://app.blocksec.com/explorer/tx/eth/0xe03809990a3650e905d60a1c1389c10800d1d2738eef18ae81e6239dbed33356), signed by the legitimate EOA, at block **23375797**. - If you simply trust that list, you conclude: > “Our initialization was the first and only one; no one else touched this proxy before us.” However, if you **debug that 23375797 initialization call**, you see that the CPIMP proxy is *already* in the middle. That, in turn, implies: - The **malicious** initialization must have occurred somewhere between the deploy at **23375794** and the “legit” initialization at **23375797**. Where is it then? - Etherscan does **not** display any direct transaction to the proxy before 23375797 in the normal “Transactions” list. - But if you switch to the **advanced view / internal transactions**, you find an internal `initialize` call at block **23375795**. - That internal call is the malicious one: - It lives inside a larger transaction ([Multicall3 tx](https://app.blocksec.com/explorer/tx/eth/0xc0b7e490caac2b8cfa5e62d1b28a5e7dba7600e623c71352acbc9b23c2b65b7c)). - Because it is not the top-level `to` of the transaction, it is not shown in the simple “TXs to this contract” list. This is part of the trick: - The **malicious initialization** was **not** a direct transaction to the proxy. - It was **wrapped in a multicall**, so the default explorer UX did not list it as a transaction “sent to” the proxy. - A developer who only checks the standard Etherscan tab sees: - Deploy at 23375794. - “First” initialize at 23375797 from the legit EOA. - No earlier interaction. - That visual narrative is wrong, but it is plausible enough, mostly if you deploy in many chains and just fast check everything. ## 4. Practical lessons from this attack - **Proxy deployment + initialization MUST be atomic.** - First of all and most important, make sure the deploy+initialize it's done atomically within a contract. - **Validate the process, don't just trust the UI.** If not atomic: Always validate that everything happened as expected. When validating a sensitive deployment: - A transaction is a single Ethereum tx, but it can contain multiple internal calls between contracts, and explorers like Etherscan often show at first sight only the top-level tx (the legit initialize) while showing calls in the internal window. Hiding in this way the internal malicious transaction. - Inspect **internal calls** not only direct txs. Inspect the full trace within the time window of the deployment/initialize. - Confirm who made the **first** `initialize` call - Compare the events & verify how many delegate calls are been made in each tx. ![image](https://hackmd.io/_uploads/BJ8t_3-fbx.png) In other words, the attacker did not just exploit the protocol’s deployment flow; they also tricked **how humans read block explorers such as Etherscan**. ## 5. References: - CPIMP explanation: https://www.youtube.com/watch?v=RShnWs0V120 - USPD exploit announcement: https://x.com/USPD_io/status/1996711283446464598?t=OBoRpE4KaqXjT1yCJwkUtw&s=35: - Proxy deployment Tx: https://app.blocksec.com/explorer/tx/eth/0x3477bb4cb7cfcd12664ca224ad8468cfe2168fa1e779333c847a02bea1623d23 - Malicious initialization Tx: https://app.blocksec.com/explorer/tx/eth/0xc0b7e490caac2b8cfa5e62d1b28a5e7dba7600e623c71352acbc9b23c2b65b7c - Legit initialization Tx: https://app.blocksec.com/explorer/tx/eth/0xe03809990a3650e905d60a1c1389c10800d1d2738eef18ae81e6239dbed33356