owned this note
owned this note
Published
Linked with GitHub
# 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).

## 2. How CPIMP is tricking you

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.

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