# Unprotected or repeatable initializer

Initializer callable by anyone or twice, writing owner, admin or implementation state

_Area: Smart contract access control and control flow. Seen in 34 disclosed reports; 4 confirmed bounties, median $125,000, range $42,069-$10,000,000; latest 2026-09-16. Updated 2026-10-23._

## How it works

An initializer is meant to run once, at deployment, to write privileged state: owner, admin, implementation address, config. The assumption that breaks is "this already ran, or only the deployer can run it." When the guard is missing, wrong, or scoped to the wrong lifetime, any caller can run it again and write their own values into storage. Proxies and clones make this worse: the implementation contract is often left uninitialized, and its fallback delegatecalls into whatever address storage points at, so controlling that storage yields control of every clone.

## Where it shows up

- `initialize`/`init`/`initialise`/`acceptManager`/`initVRF` with no access control or no one-time flag.
- Implementation contracts deployed but never initialized, or initialization reverted in a bugfix [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-wormhole-uninitialized-proxy-bugfix-review.md).
- Upgrade paths that read the implementation (e.g. `shouldUpgrade()`) and then delegatecall attacker-influenced code [E2](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-harvest-finance-uninitialized-proxies-bugfix-review-200k-bounty.md).
- Clone/proxy factories where the implementation's initializer is open [E5](https://bugbountylibrary.com/r/c4%3A2023-06-stader%3AH-01.md).
- `init()` used instead of a constructor on CREATE2-deployed contracts [E7](https://bugbountylibrary.com/r/c4%3A2025-12-panoptic-next-core%3AH-01.md).
- One-shot guards built on EIP-1153 transient storage, which is transaction-scoped, not frame-scoped [E3](https://bugbountylibrary.com/r/dhl%3A20260916-startale.md).
- Per-item clone registries with open `initialize(uint256)` [E4](https://bugbountylibrary.com/r/dhl%3A20260826-enjincryptoitems.md).

## How to review

Grep for `initialize`/`init`/`acceptManager` and confirm each has both access control and a persistent `initialized` flag. The invariant: after deployment, every initializer is either already consumed or gated so only the intended party can call it, and it can never run twice. Check each implementation contract, not just proxies, for a consumed initializer or a locked one. Confirm the one-time flag is a real persistent storage slot, not transient storage that outlives its intended frame [E3](https://bugbountylibrary.com/r/dhl%3A20260916-startale.md). Trace every delegatecall target and confirm storage it reads cannot be set by an unprivileged caller. For factory clones, verify the implementation is initialized or initializer-disabled [E5](https://bugbountylibrary.com/r/c4%3A2023-06-stader%3AH-01.md). Diff deployed bytecode against source to catch a reverted or rolled-back initialization [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-wormhole-uninitialized-proxy-bugfix-review.md).

## Variants seen

- Uninitialized implementation reachable via upgrade delegatecall, leading to selfdestruct and bricked proxy [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-wormhole-uninitialized-proxy-bugfix-review.md)[E2](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-harvest-finance-uninitialized-proxies-bugfix-review-200k-bounty.md)[E5](https://bugbountylibrary.com/r/c4%3A2023-06-stader%3AH-01.md).
- Uninitialized proxy letting attacker set implementation and drain balances [E6](https://bugbountylibrary.com/r/dhl%3A20260510-renegade.md).
- Re-callable `init()` overwriting admin after deployment [E7](https://bugbountylibrary.com/r/c4%3A2025-12-panoptic-next-core%3AH-01.md).
- Transient init flag persisting past constructor, enabling reinit drain [E3](https://bugbountylibrary.com/r/dhl%3A20260916-startale.md).
- Open registry initializer enabling manager takeover [E4](https://bugbountylibrary.com/r/dhl%3A20260826-enjincryptoitems.md).

## Why fixes fail

E1 shows a bugfix that reverted initialization, reopening `initialize()` and recreating the bug: a rollback can silently undo the one-time guard.

## Impact and severity

Critical: full takeover, fund drains ($6.4M at risk [E2](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-harvest-finance-uninitialized-proxies-bugfix-review-200k-bounty.md), 5.23M ENJ [E4](https://bugbountylibrary.com/r/dhl%3A20260826-enjincryptoitems.md), ~$209K [E6](https://bugbountylibrary.com/r/dhl%3A20260510-renegade.md)), and permanent bricking via selfdestruct [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-wormhole-uninitialized-proxy-bugfix-review.md)[E2](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-harvest-finance-uninitialized-proxies-bugfix-review-200k-bounty.md)[E5](https://bugbountylibrary.com/r/c4%3A2023-06-stader%3AH-01.md). Severity rises when implementations hold or gate large balances and when the takeover path reaches selfdestruct or arbitrary delegatecall.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-wormhole-uninitialized-proxy-bugfix-review.md
- E2: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-harvest-finance-uninitialized-proxies-bugfix-review-200k-bounty.md
- E3: https://bugbountylibrary.com/r/dhl%3A20260916-startale.md
- E4: https://bugbountylibrary.com/r/dhl%3A20260826-enjincryptoitems.md
- E5: https://bugbountylibrary.com/r/c4%3A2023-06-stader%3AH-01.md
- E6: https://bugbountylibrary.com/r/dhl%3A20260510-renegade.md
- E7: https://bugbountylibrary.com/r/c4%3A2025-12-panoptic-next-core%3AH-01.md
- E8: https://bugbountylibrary.com/r/dhl%3A20250615-walecoin.md
