Hi. I have a question on the UUPSUpgradeable contracts. Seems that it is always recommended that contracts inheriting UUPSUpgradeable should put
_disableInitializers() in its constructor, or else it would be exploitable for attackers run the
initialize() function in the implementation contract.
My question is - why isn't this enforced by a check? Or am I missing something. Thanks in advance!
Reference: Is _disableInitializers necessary?
Ok. Since no one is answering this question, I have asked ChatGPT (GPT4) and this is what I got.
my question is: why doesn't openzeppelin put _disableInitializers() in the constructor of uups upgradeable? this can prevent people from forgetting it
OpenZeppelin's UUPS upgradeable contracts don't include _disableInitializers() in the constructor by default mainly for flexibility and to cater to different use cases. Developers might have varying requirements and setups for their upgradeable contracts. By not enforcing this in the default constructor, OpenZeppelin provides developers with the flexibility to choose how to secure their implementation contracts.
However, OpenZeppelin does emphasize the importance of securing implementation contracts in their documentation, and they advise developers to invoke _disableInitializers() in the constructor to prevent unintended initialization and potential security vulnerabilities. This approach allows developers to opt for the best security practice while still accommodating diverse contract requirements and configurations.
what kind of flexibility is this? can you give any example of this flexibiltiy being good use
The flexibility of not including _disableInitializers() in the constructor in OpenZeppelin's UUPS upgradeable contracts allows for various use cases:
Testing and Development: During the development phase, especially in test environments, developers might need to initialize and reinitialize contracts multiple times. Including _disableInitializers() by default would hinder this iterative process.
Different Initialization Patterns: Some projects may require a different approach to initialization, especially those with complex upgrade patterns or those integrating with existing systems.
Advanced Use Cases: Advanced developers might implement custom initialization logic that goes beyond the standard pattern. Not enforcing _disableInitializers() by default gives them the room to implement these custom solutions.
In essence, this flexibility is advantageous for accommodating a wide range of development scenarios, catering to both standard and advanced use cases.
Hey @pkqs90, sorry for the late response.
This is a good question. If I'm correct, this is because the
_disableInitializers is not always needed but recommended. I can see how anyone will complain if they're forced to use
Honestly, this reason is a bit weak in my opinion since we generally recommend disabling initializers regardless.
In my opinion, this requires discussion. But I don't think it should be a priority rn.