The CPIMP Backdoor: Anatomy of a Multi-Chain Proxy Attack
DeFi Security Summit at Devconnect Argentina 2025 · November 2025 · 20:16
Yannis Smaragdakis, co-founder of Dedaub, gives a deep dive into the CPIMP vulnerability, a stealthy proxy-in-the-middle that infected dozens of DeFi protocols across multiple chains. The talk is an anatomy of the attack and an account of how Dedaub and SEAL 911 raced to neutralize it before it could be widely exploited.
Speakers
Topics
From DeFi Security Summit at Devconnect Argentina 2025, hosted by DeFi Security Summit.
Transcript
That won't work. >> That won't work. I'll I'll just use Yes, I'll use my laptop. Okay. Not my fault. I sent my slides 24 hours ago. Uh, okay. So, this is on the CPIMP backdoor. Obviously, a name we dubbed we dubbed the vulnerability CPM to to make it kind of memorable. Uh, again, I'm Janice from Dub. Uh this is an investigation that's joined with a bunch of people. The the main people are there David Benimol uh Seal 911 leader PC Averatio and Neville from DDOB and I'll give specific credits a little bit later. So what was this?
Yeah, sometime in the summer, uh, David had, uh, pinged us before a couple of times in the past about various vulnerabilities, but on July 8th, he actually says, "Well, guys, uh, let's look into this. I might have found something even bigger than before." And, you know, this is he was investigating something that was flagged by one of his colleagues, uh, Rashelon Casaparov, who didn't take part in the investigation afterwards. Uh but David had pushed forward and found a bunch of proxies that had been taken over by an attacker.
So this looked uh a little weird. Now we all know proxy patterns, right? They're not even a thing from the blockchain. Uh they existed even before smart contract like traditional object-oriented programming. You have an object, it has an implementation reference in it and it delegates to an implementation. Clearly in smart contracts we do it a little more in a little more sophisticated way. We use delegate call. So the storage is for the proxy but the implementation can act on that storage. I'm going fast because I think you've all seen this but just as a quick refresher uh when the proxy is initialized it gets the implementation reference. later we can
upgrade to a different implementation. That's the great thing about proxy patterns of various kinds. Now uh with all proxy patterns you have the proxy it has an implementation slot it gets updated. The big thing is that if you have not initialized the implementation anyone can go in and initialize it to any implementation they want. So that's kind of a standard thing, right? And in most cases, that wouldn't be a big deal. That's no big deal. I mean, someone took over my proxy because they initialized it before I did. I'll just deploy another proxy. I didn't do anything. I hadn't even initialized it. So I'll deploy another proxy. So all you need to do typically is be careful to check that
the initialization when you tried to initialize it, it succeeded. And then afterwards, the implementation is your implementation, what you intended. Well, yeah. So, it would seem it's no big deal. We found some proxies that were taken over. So, what? Well, it was a little more complex than that. Now, let me ask you, would you have been fooled if there was an attacker that before you tried to initialize your proxy, it was never initialized, it's just untouched. The moment you send your initialization transaction, your initialization transaction fully succeeds and emits an upgraded event that has your implementation in. So if
you're watching events, you think everything went fine. After initialization, if you ask the proxy what's your implementation, it returns the legitimate implementation, what you thought you initialized the implementation to. And you go to etherscan. You go to read write contract on etherscan and you say give me the implementation or it it prompts actually the implementation right on its own and it gives you your implementation. I think most of us would have been perfectly fooled by something like this and that's exactly what was happening here. So what's happening here is we have a proxy in the middle. That's the part that the attacker has taken over.
So we have a proxy. The implementation inside my proxy is the clandestine proxy of the attacker. This has been put in place by front running my initialization transaction. Again, that's kind of traditional, not weird to frontr run an initialization transaction. The weird thing is that this is completely hidden by most detection mechanisms. you will not be able to see this. So this stays in hiding. It's owned by the attacker.
Anything that you call, any legitimate functionality you call, for the most part, it gets forwarded to your legitimate implementation. You ask what's the imple, you get the legitimate implementation. And in here there's a whole big setup of huge functionality because this is really a proxy that delegates to other implementations and it implements very complex takeover functionality as we're going to see. So just as a couple of indications of the kinds of cool things that this clandestine proxy in the middle uh will was doing. First of all, it was preventing large large transfers. It was letting small transfers go through, but
if someone tried to get the money out of this contract, get more than 90% out in a single transfer, [clears throat] that one, it stopped it. So, it had like logic that prevented some actions, but it allowed other actions. If anyone tried to upgrade to a different implementation, we will see the code. It actually checked and reinstalled itself. So, this was something that had been going on for months. it was staying in hiding at many many services and we'll discuss that pretty soon. But the general structure is this one. We have a hidden proxy in the middle. So that's what we called the cpimp the cland clandestine uh proxy in the middle of a proxy pattern. Okay. So what were the
signs that this was there that something had been taken over? First of all the initialization transaction was front run. It actually emitted two upgraded events. it first upgraded into the implementation and then in order to fool you, it emitted an upgrade event o on the proper implementation. Secondly, the most telltale sign is that any transaction on that infected proxy, the proxy that now has been infected with the attacker's proxy has two delegate calls. So you call buy bond maybe it lets you buy the bond. It it was silent for the most time. uh the the CPMP did not try to intervene in most
transactions, but it had to do two delegate calls in the middle. First to the hidden the clandestine proxy and then to the final implementation. So those were the signs that would tell us that there's something in the middle. Okay, so we got the warning by David. Uh we had machinery to investigate the impact. Uh clearly in just a couple of hours it was clear that the impact is severe that many protocols on many chains were affected. So we called a war room. Who's better to run a war room uh than seal 911? Nobody. Uh so this was a war room uh by seal 911 and we had two tasks right away. first to determine the
impact. Uh I mean so we we had two tasks to find everyone who's affected and then to find the severity and find affected for some chains was much easier because we have a database of everything that happened on those chains. So we could just write a query. For other chains we had to watch events uh and write a scanner for blocks and it was not so easy. And to find effective just to give you an idea the first query that we did was on the initialization transaction front running. So we just checked for two upgraded events. So that was not the greatest query. Uh so it was it gave some noise. Uh the final query was a a bit uh like what I'm showing on the
slide. It both checks transactions that have delegate calls and at the same time it looks inside the decompiled code of the proxy and we found a signature that was a telltale sign that the proxy was there. So we combined a bit of decompilation with a bit of dynamic information. In the end in a few hours for the change that we could support natively in our database we had very good estimates of the coverage. What are the protocols that are affected? Okay. So I I know you were looking forward to this. Many protocols were affected and some were very very close to being exploited. Some large ones uh dodge the
bullet by very little. Um so I'm putting some of the very large ones like Pendle and Origin at the bottom because they were like Origin was marginally affected. They had a a a contract on a secondary chain that was not used uh yet. uh Pendle, they actually had found out that something was wrong before our warning and they had managed to upgrade, but they did not know exactly what was wrong with their proxies or but they dodged the bullet for sure even before our warning like a few day a couple of days before our warning. Uh so lots of protocols were infected uh on many chains and some of those we didn't have
native support for. So this was a serious investigation to find out uh what was going on there. But that kind of gives you an idea of the extent of this attack. We have a hacker. We have an attacker who was laying in weight for months having infected many many protocols. So once we figured out that this was pretty uh that everyone is affected or lots of uh protocols are affected, we had to determine severity. That's not so easy. You see that someone is infected, but how serious is it? Well, maybe you cannot even tell if you analyze the code on one chain. So, in one case, for instance, we saw that there was an
infected contract that seemed to have privileges to send a cross-chain message through layer zero. Well, we didn't know what will be the impact of a deposit message on another chain. Does it really give you funds right away? Uh so we had to communicate with the actual protocols even before we knew how serious this was. And this made the war room a little complex because it means that there were some 10 different protocols in the war room and they all needed to communicate. They all need to coordinate. So and imagine now you're a protocol. You have an attacker. Someone tells you your protocol has been infected for two months now. Well, you want to rescue
your protocol. But then that same person who warned you says, "Well, don't act yet because that will warn the attacker and will endanger everyone else. Please wait a few hours until we can do a coordinated rescue." So this was complex to say the least. And every protocol needed different strategies for recovery because the CPIMP actually had custom logic per protocol. It does custom actions per selector, per function selector. So, uh you cannot just say I'll call an upgrade and replace. Well, if you call an upgrade, the CPIP will reinstall itself. You have to somehow say, oh, if I call that function that has no special actions on it, I can
actually withdraw most of the liquidity from my protocol. So, I can put it on a new contract and I'm fine. So, many custom rescues were needed. So, this was a very hard war room. uh but for the most part we had a very successful mitigation. In the end we did uh there were a couple of protocols that were missed but compared to the overall impact it was a fairly successful rescue. So before I finish let me give a couple of ideas from the dissection of the uh attacker proxy itself. So let's go a little more technical. There's much more detail in in our blog post in our article. Uh but we decompiled the proxy and you can get some ideas uh of its
complexity. First of all, it it was a proxy that itself delegated to intermediate implementations. So it could do any of a number of specialized things. So it could have custom per protocol logic. So I already mentioned uh for most protocols it didn't allow transfers that moved more than 90% of a token out from the contract. Uh it had logic of course to restore itself post transaction in the implementation slot. It had logic for uh ERC transfer actions with permit with off-chain signatures.
So even if you blacklisted uh the original sender, you could still uh do a transfer like the attacker could still do a transfer on L2s with uh off-chain signatures instead of st starting the transaction from a blacklisted address. So it had lots of complex logic and of course it was a proxy in the end. It just for the most part delegated to the original implementation if it didn't have anything to do. And here's another very cool tidbit from looking into uh the actual attacker proxy. Here's how Etherscan was fooled. It wasn't so easy to for them to fool Ether Scan. So what
in fact they did was they took advantage of Etherscan's policy to recognize implementations from many different proxy standards. and they found an older standard and I'm sure none of you has seen this at least I hadn't seen it uh the org zeppelinos proxy implementation so that's an old proxy standard by open zeppelin so they actually went and in that stored slot here they put the legitimate implementation so etherscan saw that storage slot that was not really used by this particular proxy standard and saw that and thought, "Oh, that's the legitimate implementation." So that's
how Etherscan was fooled to report the legitimate implementation and not the the proxy the the malicious implementation that was in the middle. So they used something that obviously they found by lots of experimentation. So this was kind of cool. Okay. So in all this was a major bullet dodged for the community. Uh this was a very sophisticated hacker that was lying in wait for months waiting for big fish to fry. Not just a couple of million that they made away with in the end, but something much much bigger. Uh and it was very successfully mitigated. It was
discovered before it was exploited, but it was definitely a very sophisticated attack. Uh lots of people deserve credit for this. Uh so David Benimol uh obviously the the original reporting original find and lots of investigation in the days of the war room. uh Seal 911 uh PC Versaceio obviously led the rescue effort, coordinated the war room and actually investigated the ether scan fooling technique and then uh from our company Neville wrote the queries over the impacted protocol and reverse engineered uh the code of the malicious proxy and there's more technical detail but I think you got a pretty good idea.
This was a sophisticated proxy in the middle that was waiting to to get big fish to fry. Thank you very much. [applause] >> I left room for questions, right? >> Yeah. >> The nation the intention >> what >> they were waiting for tens of millions to go into one of those protocols. Like for instance, if they could have hid Pendle, if Pendle had used those
contracts before uh being discovered, before the attacker was discovered, if had used that those particular contracts and had major liquidity, they would have attacked. It's one of those like how we saw with a by- bit hack, right? They took over something extremely major. They took the safe they took over the safe UI but they got one big fish in the end. So they were waiting for something like that. A lot of liquidity in one of the protocols. Peter. >> Yes. >> Yiannis. Were any of the users with approvals targeted at all or drained?
>> So So >> were any of the users who approved to the protocol like infinite spend drained at all as part of this attack? >> Uh no I don't think so. I don't think we had lots of approval vulnerabilities in this in this attack. I don't think it was there was it was approval based. >> Were there methods that could do like arbitrary calls to do the drain on users in the in the back door? >> If you could do arbitrary calls with uh with those I mean I I'm not sure that there were any approvals at all to those proxy contracts. So I think obviously if there were approvals you have everything in the middle you can do you can do anything you want there. Uh so I think there were no approvals
or no major approvals anyway let's say so that's something that they may have waited for for instance one of those contracts using actually transfer from in the implementation and getting approvals and then they can do anything. I'm curious how do you you find it because it was a pretty high attack. How >> I mean if someone is watching transactions it's not uh it's not so hard to find because if you're actually dissecting a transaction at the very least you can tell there are two delegate calls or if you if you watch your initialization transaction very carefully you see sometimes you you clearly see that it's much more complex
than you expect. like it does initialization two times here pretty much. So it's not unnoticeable. It's like who pays attention to those details? If the events are right and it does the thing that I want, why would I go and trace the transaction? But someone did and then the impact was estimated. Yeah. >> Sorry, I don't get it. How could >> it's not initialized twice. What it does is it it's initialized once to the malicious proxy in the middle. So it emits the upgrade event and it emits a second upgrade event in order to fool the legitimate implement. So the legitimate deployer. So it's not initialized twice, but it sets two
references, right? And not only it sets two references, it also emits two events just to fool you. Just so you see the legitimate event and then there's another one. By the way, the estimate is that this was not North Korea. This was uh the estimate based on various things is that this was uh uh China, some Chinese hacker group. Thank you very much.