Common proxy vulnerabilities in Solidity – part 2

In the previous part, we explained some of typical proxy issues related to initialization, lack of state update or frontrunning. In this part, we would like to talk a bit about function and storage conflicts and also about decentralization.

Proxy function clashing

This vulnerability is unlikely to be found unless the proxy is a custom implementation. Using e.g. OpenZeppelin upgradeable contracts is much safer, however in the past, it was the place where this vulnerability has been found. It has been thoroughly explained in articles such as this and this, but let us summarize it in short. Look at the following code, which will not compile as we will get error as in first line:

// Error: DeclarationError: Function with same name and parameter types defined twice.
pragma solidity ^0.8.0;

contract clash {

    address owner;

    function setAdmin(address newOwner) public{
        owner = newOwner;
    }

    function setAdmin(address newOwner) public {
        require (msg.sender == owner);
        owner = newOwner;
    }

}

If such contract compiled, we would have run into trouble since unexpected things might have happened, including possibility of calling the insecure function instead of the secure one. But this is only for reference, as proxy clashing works exactly in the same way.

When a function is called by EVM, it is not however called by its name, but by its selector, which is the first 4 bytes of keccak256 hash of the string constructed of function signature (its name and arguments it takes). Below code from solidity-by-example shows how to get a signature of function:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract FunctionSelector {
    /*
    "transfer(address,uint256)"
    0xa9059cbb
    "transferFrom(address,address,uint256)"
    0x23b872dd
    */
    function getSelector(string calldata _func) external pure returns (bytes4) {
        return bytes4(keccak256(bytes(_func)));
    }
}

So if there is a hash and not function name, shouldn’t it be unique? Well, if it were for full hash, maybe, but since its just first 4 bytes, it is easy to create a collision. But it again, will not work in the same contract, since solidity compiler will be able to detect such clash. However, when a proxy is used, it is possible that a proxy might implement a function (other than standard fallback etc.) that have the same signature as a function in the implementation. In such case, the function in the proxy will be called first, which might have unexpected security implications. This behavior is already well described here.

Proxy storage clash

Another “clash” type issue concerns storage. As you probably know, proxy separates data and logic (implementation) layer. Knowing this, we also highlight that during upgrade, the logic is changed. It may contain references to some variables, which is normal thing. However, these variables are not being referenced by name, but by its order in data contract storage. So in short, if contract v1 has two variables: Owner and Manager, and contract v2 wants to implement third one, it should also implement the previous variables in the same order.

pragma solidity ^0.8.0;

contract Contractv1 {
    address Owner;
    address Manager;
}

contract Contractv2 {
    address User;
    address Owner;
    address Manager;
}

Since solidity slots in memory, in simple terms, are just a “boxes” next to each other, then in above code, if a upgrade is performed from contract v1 to v2, the new version will have the User variable referring to the same slot which previously was reserved for Owner. This may result in unexpected circumstances. Also that behavior is extensively described here.

Decentralization concerns

It of course should be noted that upgradeability breaks the idea of immutability – if a contract can be upgraded, then its code can be changed by anyone who have access to proper deployer key. It is extremely important that the deployer address is not a standalone entity but rather a multisignature wallet, which especially in case of a compromise of single admin, will not lead to replacing the contract with malicious one.

Article, News & Post

More Post

A guide to reentrancy: abusing the external calls for fun and profit

The reentrancy vulnerability is one of most serious ones that can be found in solidity smart contracts. Apart from the “classic” reentrancy like the one from the infamous DAO hack, there are other types of this vulnerability. In this article, we describe them along with some popular strategies on how

Ethereum signatures for hackers and auditors 101

In real world you can sign documents using your personal signature, which is assumed to be unique and proves that you support, acknowledge or commit something. The same can be done on ethereum blockchain and in solidity smart contracts – but using cryptography. In this article, we will briefly explain

Common proxy vulnerabilities in Solidity – part 2

In the previous part, we explained some of typical proxy issues related to initialization, lack of state update or frontrunning. In this part, we would like to talk a bit about function and storage conflicts and also about decentralization. Proxy function clashing This vulnerability is unlikely to be found unless

Automated auditing part 2 – usage of AI for Smart Contracts testing

Introduction Creating a project or solution from scratch is a difficult and time-consuming process. A business concept must first be developed, then it must be translated into a high-level solution architecture, and finally the software development stage takes place. Because we will be focusing on hypothetical smart contracts in this

Common proxy vulnerabilities in Solidity part 1

Proxies are used to implement upgradeability in Solidity smart contracts. They serve as a middleman between a contract and its users. They are employed to change a contract’s logic without altering its address. A master copy contract and a proxy contract that refers to the master copy are how proxies

Echidna - Wikipedia

Automated auditing part 1 – fuzzing with Echidna

What is Echidna? In this part, we will cover the very basics of Echidna usage. Echidna is an animal, but it is also the name of a Solidity fuzzer. This tool is really worth mastering since a skilled user can be able to test a smart contract with it in