OpenZeppelin Contracts is a widely used library for the development of secure smart contracts in the Ethereum ecosystem. Recently, a vulnerability with the CVE identifier CVE-2022-39384 was discovered in OpenZeppelin Contracts versions 3.2. to 4.4., affecting the initializer functions under specific conditions. This post will provide an in-depth analysis of the vulnerability, along with code snippets, links to original references, and details about available patches and workarounds.

Vulnerability Details

Before version 4.4.1 but after 3.2., initializer functions that are invoked separately from contract creation (such as minimal proxies) may be vulnerable to reentrancy attacks if they make an untrusted non-view external call. In general, once an initializer has finished executing, it can never be run again. However, an exception in place to support multiple inheritance enables reentrancy in the scenario mentioned, which breaks the expectation of single execution.

Here's an example of a vulnerable contract using OpenZeppelin Contracts 4.4.

pragma solidity ^.8.;

import "@openzeppelin/contracts/proxy/utils/Initializable.sol";

contract VulnerableContract is Initializable {
    uint256 public value;
    
    function initialize(uint256 _value) public initializer {
        value = _value;
        // Untrusted external call, potentially leading to reentrancy
        someUntrustedExternalCall();
    }

    function someUntrustedExternalCall() internal {
        // ...
    }
}

Exploit

An attacker could potentially manipulate the vulnerable contract by reentering the initializer function, causing several unwanted side effects such as overwriting the contract state or executing functions multiple times.

Original References

1. OpenZeppelin Contracts GitHub repository: https://github.com/OpenZeppelin/openzeppelin-contracts
2. OpenZeppelin Contracts release notes for version 4.4.1: https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.4.1
3. CVE entry for CVE-2022-39384: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39384

Patch and Workaround

To fix this issue, users are advised to upgrade their OpenZeppelin Contracts dependency to version 4.4.1 or later. The updated library includes a patch to prevent reentrancy in the initializer functions.

// Update your dependency in package.json
"@openzeppelin/contracts": "^4.4.1"

As a temporary workaround, you can avoid making untrusted external calls during the initialization process. This may not always be feasible, so upgrading to the patched version is the recommended approach.

Conclusion

The OpenZeppelin team has identified and patched the reentrancy vulnerability in the Contracts library with the release of version 4.4.1. Users are strongly recommended to update their dependency to this version or later, and be cautious when making untrusted external calls during the initialization process. While upgradeable proxies are commonly initialized together with contract creation (where reentrancy is not possible), it is essential to stay aware of potential risks and concerns when using OpenZeppelin Contracts in your projects.

Timeline

Published on: 11/04/2022 22:15:00 UTC
Last modified on: 11/07/2022 17:07:00 UTC