---
# System prepended metadata

title: Meerkat.Finance - Malicious Proxy Incident - Post Mortem

---

# Meerkat.Finance - Malicious Proxy Incident - Post Mortem

## Summary



*   [Meerkat.Finance](https://meerkat.finance) (offline), a yield-farming project recently started on Binance Smart Chain (BSC) has been drained for 13,968,039 in **BUSD** (Binance-pegged USD) and 73,635 in **WBNB** (Wrapped BNB), leading to **loss of $31.56 million in funds**.
*   While the project team claimed being hacked due to various vulnerabilities, the on-chain data tells a very different story indicating a planned exit scam AKA "rug pull".
> The team behind Meerkat Finance, a yield farming pool running on the Binance Smart Chain that went live just one day ago, claimed in its official Telegram channel around 9:00 UTC on Thursday that its smart contract vault was compromised.

(*via* The Block) [[1](https://www.theblockcrypto.com/linked/97082/rug-pull-defi-meerkat-31-million)]

*   Meerkat Finance Deployer upgraded 2 vaults of the project.
*   Attacker address calls permissionless initialization function through the Vault proxies, effectively allowing anyone to become the Vault owner [[2](https://bscscan.com/tx/0xfcf48681e382e9f9cc1d6a64ff30487306f6b869924c6594075fcc86b3b21f5d)]
*   Attacker subsequently drains Vaults by calling a function with signature 0x70fcb0a7 which accepts a token address as an input. Decompilation of the upgraded-to Smart Contract shows the only use of the invoked function to be removal of funds with the owner as beneficiary.

> This is not wrong, but ususally if the a contract has a function which allows the owner to retrieve the assets which are used in the strategy/vault actively, then you are basically placing your trust in the project team. They can pull the plug any time. That's why projects like yearn add checks like in the image below, so that the team can only rescue the funds which are not in active use by the strategy/vault.
> 


![](https://i.imgur.com/9hV83Qa.jpg)
*(Example usage of a "rescue token" style method. Thanks [@vasa_develop](https://twitter.com/vasa_develop).)

## Details

Both affected Vaults used OpenZeppelin's Transparent Proxy Upgrade pattern, allowing to upgrade the Vault logic to a new logic implementation by calling the function *upgradeTo(address newImplementation)* on the Vault proxy level.

The BUSD Vault's previous implementation is located at 0x49509a31898452529a69a64156ab66167e755dfb, the WBNB Vault's previous implementation is located at 0x3586a7d9904e9f350bb7828dff05bf46a18bb271, both being rather inconspicious and verified contracts.

Meerkat Finance Deployer calls *upgradeTo()* two times:
* at block 5381239, setting WBNB Vault implementation to *0x9d3a4c3acee56dce2392fb75dd274a249aee7d57* [[3](https://bscscan.com/tx/0x063970f8625f250101a7da8abf914748cf8eaaaa9458041f1928501accfe5d6c)]
* at block 5381246, setting BUSD Vault implementation to 0xb2603fc47331e3500eaf053bd7a971b57e613d36 [[4](https://bscscan.com/tx/0xf19fa4bcff4adaebeddd28c851458ba0f01ffedd52b62df56ace94e7c8842553)]

changing the Vault logic to introduce two noteworthy functions that have not been part of the initial implementations.

* *init(address owner)*
According to decompiled bytecode this function sets the address on storage slot 0 to the address provided to the function.

There's no permission check, making this newly added function the ultimate backdoor into the Vaults.

Using a specific Initializer pattern in transparent proxies is best-practice and was also applied in the first Vault implementations, so it is highly questionable what was the intend to add the *init()* method other than a planned theft of Vault funds.

* *0x70fcb0a7(address _param1)*
Source code is not available, decompiled source is limited to checking that the caller is equal to storage slot 0 set in *init()* method and transfering out the balanceOf() on the token contract supplied with *param1*, using the Vault address as the query target.

Both functions are not part of the previous Vault implementations.
Comparing the bytecode size of old and new implementations it can be stated that the new implementation is only 1/4th the size of the previous logic.

Since the upgrades where done by the Meerkat Finance Deployer the most likely scenario given all aspects of the on-chain data is an intentional "rug pull" while granted there is a small chance of private key compromisation.

The latter doesn't explain why the project went dark after the incident. Stay safe and draw your own conclusions.

As of the time of writing funds have partially been split among various addresses and sent to what seemingly belongs to the Binance Bridge hosted by Binance exchange.

The Binance.org Bridge is currently suspended, probably to avoid the funds from being easily moved to other chains.

## Timeline (04.03.2021)


* **Mar-04-2021 08:53:10 AM +UTC**
Meerkat Finance Deployer [upgrades](https://bscscan.com/tx/0x063970f8625f250101a7da8abf914748cf8eaaaa9458041f1928501accfe5d6c) WBNB Vault to contract 0x9d3a4c3acee56dce2392fb75dd274a249aee7d57

* **Mar-04-2021 08:53:31 AM +UTC**
Meerkat Finance Deployer [upgrades](https://bscscan.com/tx/0xf19fa4bcff4adaebeddd28c851458ba0f01ffedd52b62df56ace94e7c8842553) BUSD Vault to contract 0xb2603fc47331e3500eaf053bd7a971b57e613d36

* **Mar-04-2021 08:54:31 AM +UTC**
Attacker [calls](https://bscscan.com/tx/0x1332fadcc5378b1cc90159e603b99e0b73ad992b1e6389e012af3872c8cae27d) method *0x70fcb0a7* on **BUSD Vault** to transfer out *13,968,039* **BUSD**

* **Mar-04-2021 08:54:55 AM +UTC**
Attacker [calls](https://bscscan.com/tx/0xd8145dfe255a671428b9c082a006a145fe58d82175671e8bfbe02f4040ae8cd0) method *0x70fcb0a7* on **WBNB Vault** to transfer out *73,635* **WBNB**