Why you should never approve proxy smart contracts for token spending?

If the clickbait title brought you here let me start with a relieving comment, you have probably interacted with some proxy smart contracts and you will continue interacting with them without noticing. Most of them are safe. However, proxy smart contracts can be easily used to steal money from your wallet without your notice. I will try to explain how it can be done and how you can protect yourself.

Photo by Jason Pofahl on Unsplash

What are proxy smart contracts?

Smart contracts which get deployed to the blockchain are immutable like most of the things related to blockchains. This means when a smart contract is deployed its source code can’t be changed and it is set in stone forever. However, there is the concept of proxies that make your contracts updateable. In a nutshell, proxies are smart contracts that get deployed separately and can copy the code (implementation) of another contract. Which contract they copy can be updated with a simple function call whenever the owner wants. (This is achieved with Solidity’s delegatecall function. If you are interested in learning more about proxies you can start by reading OpenZeppelin’s documentation.)

For example, let’s say there is the proxy contract A and it copies the code of contract B. When you want to update how your contract works, you can deploy a new contract C and make A copy its implementation. As users only interact with A regarding transactions, nothing gets changed on their side.

What are approvals?

When we talk about a coin it usually means an ERC-20 token. ERC-20 is a standard and it comes with some essential functions. One of them is the transfer(), and you use that function, for example, when you are transferring $USDC to your friends. There is also another function which is transferFrom(), which lets other addresses transfer your funds. For example, a smart contract that lets you mint an NFT for some amount of $USDC will call this function during minting. However, without any protection everybody will be able to transfer other people’s funds, this is where the approvals come into play.

In the NFT minting example above, if the price of mint is 100 $USDC, you first need to approve the NFT contract to spend at least 100 $USDC of your own. Only after you call the approval function (which is also a part of the ERC-20 standard), your call to the mint function will not fail.

For ease of use and not to bother users with approvals all the time, DAPPs usually make you approve the spending of 1.1579209e+77 tokens (the max possible number for an unsigned 256-bit integer). This means you basically give them access to all your tokens. This is not a problem with reputable protocols as their smart contract is open-source and you can check their functions to see if they can abuse this approval.

How to exploit approvals with proxies?

Let's assume an exploiter first creates a simple banking smart contract that allows you to deposit some tokens into it and withdraw your balance. The smart contract will look something similar to the below one:

The exploiter then creates a proxy smart contract and copies this code’s implementation and develops a website that lets you interact with the proxy. (0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56 is the contract address of $BUSD on Binance Smart Chain if you are wondering.)

Then you want to use the contract and through its front-end, you approve it for $BUSD spending but you don’t check the amount of approval.

The exploiter, later on, can update the proxy to implement a malicious version of the above smart contract which can look like the example below:

After the proxy is updated, the steal() function can be used to transfer the funds of the people who have given approval to the contract in the first place.

For example, if you had 100 $BUSD in your wallet and gave an “infinite” amount of approval and only deposited 50 $BUSD. The exploiter can transfer the other 50 $BUSD directly into their wallet.

How to protect yourself?

You can, in theory, never give more approval than the amount you will use before every transaction. But in practice, this will make your life really hard as you would, for example, need to go through two transactions every time you use Uniswap instead of one.

A more practical solution would be only giving infinite approvals to reputable smart contracts which are not proxies. You can check if a smart contract is a proxy on Etherscan, or on its forks for other chains, pretty easily. And if you see the contract is a proxy, it is better not to use it at all or be careful with the amount you are approving for.

Stay safe!

--

--