Missing _disableInitializers() in constructor allows initialization of implementation contracts
Bridge, WrappedToken, MockERC20, and WrappedTokenFactory have no constructor calling _disableInitializers(), violating the OpenZeppelin defense-in-depth pattern for UUPS implementations.
Description
KeyLogRegistry correctly prevents initialization of the implementation
contract by calling _disableInitializers() in its constructor:
/// @custom:oz-upgrades-unsafe-allow constructorconstructor() {_disableInitializers();}
However, four other UUPS upgradeable contracts, Bridge, WrappedToken,
MockERC20, and WrappedTokenFactory, have no constructor and therefore
leave their implementation contracts initializable.
This means anyone can call initialize() directly on the bare
implementation contract (not the proxy), setting arbitrary values for
bridge, owner, and other initialization parameters. While this does
not affect existing proxies (each proxy has its own storage), it violates
the defense-in-depth pattern that OpenZeppelin explicitly recommends for
all UUPS contracts.
Recommendation
Add the standard constructor to all UUPS upgradeable contracts:
/// @custom:oz-upgrades-unsafe-allow constructorconstructor() {_disableInitializers();}
Resolution
YadaCoin, Confirmed.
Zealynx, Fixed.

