DistributionV2 contract inheriting UUPSUpgradeable so overriding _authorizeUpgrade() function. But adding no access control to this function can lead to setting implementation contract by anyone since this function is called for authorization in UUPSUpgradeable. By setting any malicious contract as implementation attacker can selfdestruct() the proxy contract. Since implementation is called using delegatecall from proxy.
contracts/mock/DistributionV2.sol
Since DistributionV2 contract is inheriting UUPSUpgradeable from openzeppelin we can see in upgrading implementation address _authorizeUpgrade() is called.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol#L86C5-L90C1
DistributionV2 implementation contractFirst attacker will call upgradeToAndCall to main proxy contract which will change the implementation contract address to his malicious DistributionV2 contract.
Now Attacker will call createPool to main proxy contract of DistributionV2 and by delegatecall proxy will call implementation contract .It will destroy the main proxy contract using selfdestruct(). And erase all the storage from main proxy contract of DistributionV2.
The main proxy contract will be destroyed and erase all the storage from main proxy contract of DistributionV2.
Manual Review
Add proper access control to _authorizeUpgrade() function since it is used for authorization at the time of changing implementation contract address. This can be mitigated by using 'OwnableUpgradeable' of openzeppelin and add onlyOwner modifier to the _authorizeUpgrade() function so. Only owner can be authorized to upgrade the implementation address. Add one initalizer function also to initialize the owner.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.