F-2026-0011·missing-rotation-path

No update path creates a chicken-and-egg risk with Timelock address being immutable

Fixedvaultleveragedprediction-marketgithub.com/bloom-art/dripster-lend
TL;DR

setTimelock is a one-shot reinitializer with no companion updateTimelock function; if the timelock contract becomes inoperable, capital withdrawal, admin rotation, and upgrades are permanently frozen.

Severity
INFO
Impact
LOW
Likelihood
LOW
Method
MManual review
CAT.
Complexity
LOW
Exploitability
LOW
02Section · Description

Description

setTimelock() at L254 uses reinitializer(2) and checks timelock != address(0), making it a one-shot setter. Once set, there is no updateTimelock function. The timelock address is permanent for the life of V1.

The timelock gates three critical operations via onlyTimelock: updateAdmins (L276), withdrawCapital (L361), and _authorizeUpgrade (L1685). If the timelock contract becomes inoperable (contract bug, governance locked, keys lost), the vault is permanently frozen:

  • No upgrades possible
  • No admin address changes possible
  • No capital withdrawal possible
  • The globalAdmin retains pause/unpause, addCapital, updateLimits, and updateFeeAdmin, but can never recover the capital pool

Every other privileged address in the contract (globalAdmin, emergencyAdmin, appAdmin1/2, feeAdmin, feeReceiver) is changeable via updateAdmins. The timelock is the only permanently immutable address.

The timelock is likely an OpenZeppelin TimelockController with its own role management, so it is not entirely ungovernable. However, from the vault's perspective, it is forever bound to one address with no on-chain migration path.

03Section · Recommendation

Recommendation

Add a timelock-gated updateTimelock function so the existing timelock can authorize its own replacement:

solidity
function updateTimelock(address newTimelock) external nonReentrant onlyTimelock {
if (newTimelock == address(0)) revert ZeroAddress();
address oldTimelock = timelock;
timelock = newTimelock;
emit Events.TimelockUpdated(oldTimelock, newTimelock, block.timestamp);
}

Alternatively, if the team considers this an accepted architectural constraint, document it explicitly so future operators are aware of the permanence.

04Section · Resolution

Resolution

Fixed. updateTimelock added, gated onlyTimelock; preserves the on-chain delay model for any rotation.

Status
Fixed
F-2026-0011

oog
zealynx

Smart Contract Security Digest

Monthly exploit breakdowns, audit checklists, and DeFi security research — straight to your inbox

© 2026 Zealynx