Proxy & Upgradeability Risks
Proxy patterns enable contract upgradeability but introduce risks like storage collisions, uninitialized implementations, and unauthorized upgrades that can compromise the entire protocol.
How It Works
Proxy contracts delegate calls to implementation contracts. If the storage layout between proxy and implementation doesn't match, or if the implementation can be initialized by anyone, attackers can take control of the proxy.
Real-World Examples
Wormhole (Uninitialized)
An uninitialized implementation contract allowed an attacker to set themselves as guardian and mint wrapped ETH.
Audius
A storage collision in the proxy contract allowed an attacker to modify governance parameters.
Code Examples
Vulnerable Code
// VULNERABLE: Uninitialized implementation
contract VaultV1 is Initializable {
address public owner;
function initialize(address _owner) external initializer {
owner = _owner;
}
// If deployed without calling initialize,
// anyone can become owner!
}Secure Code
// FIXED: Constructor disables initialization on implementation
contract VaultV1 is Initializable, UUPSUpgradeable, OwnableUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(address _owner) external initializer {
__Ownable_init(_owner);
__UUPSUpgradeable_init();
}
}Prevention
- Use OpenZeppelin's transparent or UUPS proxy patterns
- Disable initializers in the implementation constructor
- Verify storage layout compatibility between upgrades
- Use multi-sig or timelock for upgrade authorization
Related Vulnerabilities
Scan Your Contract for Proxy & Upgradeability Risks
Our AI-powered auditor automatically detects proxy & upgradeability risks and 20+ other vulnerability types. Get a detailed report in minutes.