CREATE2 Collision Remediation
Overview
Related Detector: CREATE2 Collision
CREATE2 deploys to a deterministic address, keccak256(0xff, deployer, salt, initCodeHash). If an attacker can predict or control the salt or init code, they can pre-compute the address and race the deployment, or exploit the selfdestruct-then-redeploy trick to place different code at an address other contracts already trust. The remediation is to make the salt unpredictable and to never treat a CREATE2 address as permanently bound to specific code.
Recommended Fix
Before (Vulnerable)
function deploy(bytes memory initCode, uint256 userSalt) external returns (address addr) {
// Caller fully controls the salt — the deployed address is attacker-chosen.
assembly { addr := create2(0, add(initCode, 0x20), mload(initCode), userSalt) }
}
After (Fixed — bind the salt to unpredictable context)
function deploy(bytes memory initCode, bytes32 userSalt) external returns (address addr) {
// Mix in msg.sender (and other non-attacker-controlled context) so the caller
// cannot freely choose the resulting address.
bytes32 salt = keccak256(abi.encodePacked(msg.sender, userSalt));
assembly { addr := create2(0, add(initCode, 0x20), mload(initCode), salt) }
require(addr != address(0), "Deploy failed");
}
Never assume the code at a CREATE2 address is immutable: if the deployed contract contains selfdestruct, it can be removed and a different contract redeployed to the same address. Avoid selfdestruct in CREATE2-deployed logic that others trust.
Common Mistakes
- Deriving the salt purely from user input, letting an attacker target a specific address.
- Trusting a CREATE2 address as an identity when the deployed code can self-destruct and be replaced.
- Reusing the same salt and init code across chains, so an address controlled on one chain implies control on another.