defirisk.co
rubric v1.7.0

Reinitializable implementation (no _disableInitializers)

A post-deploy hygiene & change mgmt factor in the v1.7.0 rubric. Measured per protocol on a s cadence.

Critical factor. A Red on this factor alone is sufficient to gate a protocol to grade D or F regardless of other category rollups.

Methodology how we score#

What this measures
This factor identifies whether an upgradeable proxy's implementation contract fails to call _disableInitializers() in its constructor, leaving the initialize() function callable on the bare implementation address. OpenZeppelin's upgradeable contract guidance recommends including "a flag so that you can't initialize a logic contract more than once" to prevent this vulnerability. Without _disableInitializers(), an attacker can call initialize() directly on the implementation contract, claim ownership or admin roles, and — depending on how the proxy's storage is structured — potentially execute a privileged drain through the proxy.

Why it matters
Reinitializable implementations represent a proxy takeover pattern that is both automated and deterministic: an attacker scans newly deployed upgradeable contracts for unprotected initialize() functions on the implementation address, calls them, and establishes an unauthorized admin role before the legitimate protocol team or users are aware. The Dedaub/SEAL911 "CPIMP" research documented this attack class publicly in 2024; USPD lost $1M after an attacker front-ran the initialize transaction and waited 78 days for TVL to accumulate before executing the drain. The Raft protocol loss ($3.3M, 2023) illustrates a related delegatecall storage pattern where unguarded initialization state caused attacker funds to route unexpectedly. OpenZeppelin's proxy pattern documentation explicitly flags that implementation contracts must be treated as separately attackable surfaces.

Green / Yellow / Red
Green is assigned when the implementation contract calls _disableInitializers() in its constructor (verified via static analysis or source inspection), or when the implementation is deployed behind an initializer modifier that is already set before deployment completes. Yellow covers cases where the initialize function exists and is unprotected on the implementation but the proxy's admin is a trusted multisig that has already initialized the state, reducing the exploitability window. Red is assigned when static analysis confirms the implementation contract has an initialize() function callable by any address with no _disableInitializers() call in the constructor.

Common gray cases
This factor is grayed when the proxy architecture does not use an upgradeable pattern (immutable contracts, Beacon-without-initialize, or UUPS with fully locked implementation), or when the implementation's constructor is not accessible for analysis.

Notable historical examples
- Raft ($3.3M, 2023): Delegatecall into implementation with uninitialized storage slot caused funds to route to the burn address; pattern adjacent to unguarded initialization state.

★ Critical factor
This factor alone is sufficient to trigger a D or F grade under rubric v1.5 — a single red assessment here overrides all other category scores. An unprotected initialize() function on an implementation contract creates a front-runnable proxy takeover vector that can establish unauthorized admin control before any user interaction — a one-transaction full account takeover with no code-quality mitigation available after deployment.

Measurement what to look for#

Determine whether the implementation contract does not call `_disableInitializers()` in its constructor, leaving re-initialization possible.

Data & output #

Data source
Source search for `_disableInitializers()` in constructor + Slither `unprotected-upgrade` detector on Etherscan-verified source
Output format
Green / Yellow / Red · critical gate active
Evidence artifact
Source excerpt of constructor + `_disableInitializers()` presence flag
Confidence signal
green = `_disableInitializers()` present in all implementation constructors; red = any implementation constructor missing `_disableInitializers()`; gray = source unverified or no proxy pattern

Scored protocols 0 carry this factor#

No protocols have been scored for this factor yet.

Linked hacks 4 historical incidents#

illustrativeAave V3: CAPO (Correlated Asset Price Oracle) misconfigured price feed for a freshly-listed correlated asset → mispriced collateral → cascade of involuntary liquidations2026-03-12 · $862K · CAPO (Correlated Asset Price Oracle) misconfigured price feed for a freshly-listed correlated asset → mispriced collateral → cascade of involuntary liquidations · Cat 9 post-deploy hygiene gap; new-listing process did not include parameter-set validation prior to activation
illustrativeCurve LlamaLend: Empty-market donation attack on a freshly-listed lending market2026-03-02 · $240K · Empty-market donation attack on a freshly-listed lending market · LlamaLend factory did not back-port the first-depositor fix from mainnet Venus / Compound III
relatedVenus Protocol (zkSync Era deployment): Empty-market donation attack on a freshly-deployed market with no virtual liquidity / no `_decimalsOffset()` first-depositor protection2025-03-29 · $902K · Empty-market donation attack on a freshly-deployed market with no virtual liquidity / no `_decimalsOffset()` first-depositor protection · Cross-chain deployment did not back-port mainnet first-depositor protection before listing — Cat 9 hygiene failure
relatedRaft: Flash loan + collateral inflation via position liquidation → infinite R mint → stablecoin dump2023-11-10 · $3M · Flash loan + collateral inflation via position liquidation → infinite R mint → stablecoin dump · ★ Reinitializable implementation [via cross-hack: Factor 45: Delegatecall Uninitialized Storage Slot]
rubric_version v1.7.0factor RD-F-143category 9carried 0critical yes