Headline
CVE-2021-41264: Restrict upgrade to proxy context in UUPSUpgradeable · OpenZeppelin/openzeppelin-contracts@024cc50
OpenZeppelin Contracts is a library for smart contract development. In affected versions upgradeable contracts using UUPSUpgradeable
may be vulnerable to an attack affecting uninitialized implementation contracts. A fix is included in version 4.3.2 of @openzeppelin/contracts
and @openzeppelin/contracts-upgradeable
. For users unable to upgrade; initialize implementation contracts using UUPSUpgradeable
by invoking the initializer function (usually called initialize
). An example is provided in the forum.
Permalink
Browse files
Restrict upgrade to proxy context in UUPSUpgradeable
Co-authored-by: Francisco Giordano [email protected] (cherry picked from commit 6241995)
- Loading branch information
Showing with 23 additions and 3 deletions.
- +4 −0 CHANGELOG.md
- +19 −3 contracts/proxy/utils/UUPSUpgradeable.sol
@@ -1,5 +1,9 @@
Changelog
4.3.2
* `UUPSUpgradeable`: Add modifiers to prevent `upgradeTo` and `upgradeToAndCall` being executed on any contract that is not the active ERC1967 proxy. This prevents these functions being called on implementation contracts or minimal ERC1167 clones, in particular.
4.3.1 (2021-08-26)
* `TimelockController`: Add additional isOperationReady check.
@@ -17,16 +17,32 @@ import "…/ERC1967/ERC1967Upgrade.sol";
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is ERC1967Upgrade {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, “Function must be called through delegatecall”);
require(_getImplementation() == __self, “Function must be called through active proxy”);
_;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeTo(address newImplementation) external virtual {
function upgradeTo(address newImplementation) external virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallSecure(newImplementation, bytes(“”), false);
_upgradeToAndCallSecure(newImplementation, new bytes(0), false);
}
/**
@@ -37,7 +53,7 @@ abstract contract UUPSUpgradeable is ERC1967Upgrade {
*
* Emits an {Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallSecure(newImplementation, data, true);
}