59691 sc low missing disableinitializers allows direct implementation initialization leading to vault takeover
Submitted on Nov 14th 2025 at 21:49:43 UTC by @gklptrgt for Audit Comp | Firelight
Report ID: #59691
Report Type: Smart Contract
Report severity: Low
Target: https://github.com/firelight-protocol/firelight-core/blob/main/contracts/FirelightVault.sol
Impacts:
Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)
Description
Brief/Intro
The FirelightVault implementation contract is missing the _disableInitializers() call in its constructor, allowing anyone to directly initialize the implementation contract itself rather than going through the proxy. If exploited in production, this could allow an attacker to take control of the implementation contract, manipulate vault logic, and potentially compromise user funds through state corruption.
Vulnerability Details
FirelightVault contract lacks the critical security measure of disabling initializers on the implementation contract. Without _disableInitializers() in the constructor, the implementation contract remains vulnerable to direct initialization attacks.
contract FirelightVault is
FirelightVaultStorage,
ERC4626Upgradeable,
AccessControlUpgradeable,
PausableUpgradeable,
ReentrancyGuardUpgradeable
{
// ...
// Missing constructor with _disableInitializers()
@> /// @custom:oz-upgrades-unsafe-allow constructor
@> constructor() {
@> _disableInitializers();
@> }
// ...
function initialize(
IERC20 _asset,
string memory _name,
string memory _symbol,
bytes memory _initParams
) public initializer {
InitParams memory initParams = abi.decode(_initParams, (InitParams));
__ERC20_init(_name, _symbol);
__ERC4626_init(_asset);
__Pausable_init();
__ReentrancyGuard_init();
__AccessControl_init();
// ...Impact Details
Direct Impact: Attacker gains administrative control over the implementation contract.
Manipulation of vault logic affecting user returns
State corruption leading to incorrect share calculations
Privilege escalation allowing further attacks
Potential fund loss through manipulated withdrawal logic
References
OpenZeppelin Documentation, Avoid leaving a contract uninitialized: https://docs.openzeppelin.com/contracts/5.x/api/proxy#caution:~:text=Avoid%20leaving%20a%20contract%20uninitialized.
Proof of Concept
Proof of Concept
I created a test file called vulnerability.js in the test directory that demonstrates the vulnerability. You can run this test on your local environment to verify the issue:
File: test/vulnerability.js
Then run the test file with following command.
npx hardhat test test/vulnerability.js --verbose
Expected Result: The test will pass, demonstrating that an attacker can directly initialize the implementation contract and gain administrative control.
Fix
As stated in OpenZeppelin documentation, add the following constructor to your contract to prevent direct initialization attacks:
This security measure prevents anyone from initializing the implementation contract directly, ensuring all interactions must go through the proxy where access control and security checks are properly enforced. Be sure to check the documentation for further details of this security mitigation.
Was this helpful?