Codehash vulnerabilities

From WEB3 Vulnerapedia
Jump to navigation Jump to search

The addr.codehash property returns the keccak256 hash of the addr EVM bytecode[1].

Balance dependency

In the contract below, you can see that the property's output depends on the balance of an address (if the address has no code deployed):

pragma solidity 0.8.23;

contract Test1 {
    address subject = address(123);

    function getCodehash()
        external
        payable
        returns (
            bytes32 codeHashBefore,
            bytes32 codeHashAfter,
            bytes32 hashBefore,
            bytes32 hashAfter
        )
    {
        hashBefore = subject.codehash;
        codeHashBefore = keccak256(subject.code);

        payable(subject).transfer(1);

        hashAfter = subject.codehash;
        codeHashAfter = keccak256(subject.code);
    }
}

The function's output:

{
	"0": "bytes32: codeHashBefore 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
	"1": "bytes32: codeHashAfter 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
	"2": "bytes32: hashBefore 0x0000000000000000000000000000000000000000000000000000000000000000",
	"3": "bytes32: hashAfter 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
}

As you can see, hashBefore (the balance is 0) is equal to 0, and hashAfter (the balance is 1) is equal to keccak256("").

The combination of the frontrunning and this issue can be used to cause a revert in functions that use .codehash to distinguish smart contracts and EOA[2].

You can see more about why this is happening in the EIP-1052 and EIP-161.