# Initialization

> Detect initialization bugs in upgradeable contracts — missing `_disableInitializers()`, re-init attacks, parent-init not chained, constructor-vs-initializer confusion, public `initialize`. Activate on OZ Upgradeable, UUPS, Transparent proxy, Initializable, or any contract with `initialize` / `__init`.

- **Type:** Skill
- **Install:** `agentstack add skill-omermaksutii-rugproof-initialization`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [omermaksutii](https://agentstack.voostack.com/s/omermaksutii)
- **Installs:** 0
- **Category:** [Security](https://agentstack.voostack.com/c/security)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [omermaksutii](https://github.com/omermaksutii)
- **Source:** https://github.com/omermaksutii/RugProof/tree/main/skills/initialization
- **Website:** https://omermaksutii.github.io/RugProof

## Install

```sh
agentstack add skill-omermaksutii-rugproof-initialization
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Initialization detection

## When this applies

- OZ `Initializable` / `*Upgradeable` contracts
- Custom upgradeable contracts with `initialize()` functions
- Beacon proxies, UUPS, Transparent — all flavors
- Factory-deployed clones (EIP-1167 minimal proxies)
- Any deploy script that uses `delegatecall` for setup

## Detection patterns

### Implementation contract not init-locked (CRITICAL)
```solidity
contract Vault is Initializable, OwnableUpgradeable {
    function initialize() external initializer {
        __Ownable_init(msg.sender);
    }
    // ← no constructor disabling initializers
}
```
Anyone can call `initialize` on the *implementation* address directly. Fix:
```solidity
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() { _disableInitializers(); }
```

### Public initializer on deployed proxy (CRITICAL)
Proxy deployment script forgets to call `initialize` atomically → attacker calls it first → owns the contract.
Fix: deploy + initialize in same tx via factory or initializer-on-deploy proxy.

### Re-init via `reinitializer(N)` accessible to anyone (HIGH)
```solidity
function reinitialize() external reinitializer(2) {   // ← no auth
    __Pausable_init();
}
```
Add `onlyOwner` or `onlyProxyAdmin`.

### Parent init not called (HIGH)
```solidity
function initialize() external initializer {
    // __Pausable_init() missing — pausable state defaults to wrong values
}
```
Verify every parent's `__X_init()` is chained.

### Logic in constructor instead of initializer (HIGH for upgradeable)
```solidity
constructor() OwnableUpgradeable() { owner = msg.sender; }   // ← runs on impl, not proxy
```
Upgradeable contracts must do setup in `initialize`, not constructor.

### Constructor runs on proxy (incorrect mental model) (MEDIUM)
Devs sometimes write constructor logic expecting it to run on the proxy. It doesn't — constructor runs at deployment of the *implementation*, and the proxy never re-runs it.

### Clones (minimal proxies) without per-clone init guard (HIGH)
EIP-1167 clones share implementation; each clone's `_initialized` slot starts at 0. If `initialize` has no auth, anyone can initialize a fresh clone before the deployer.

### Re-init via storage-slot manipulation (HIGH)
OZ v4: `_initialized` is uint8; v5: `_initialized` is uint64. Custom upgradeable contracts that don't use OZ may have bypassable guards.

## Severity rubric

| Pattern | Severity |
|---|---|
| Implementation init not disabled (anyone owns impl) | **Critical** |
| Deployed proxy with public init un-called | **Critical** |
| Re-initializer with no auth | **High** |
| Clones with no atomic init | **High** |
| Parent `__init` missing → broken inheritance | **High** |
| Constructor used instead of initializer (upgradeable) | **High** |
| Initializer parameter validation missing (e.g. zero-address admin) | **Medium** |
| Initial state value seems wrong (defaults to 0) | **Medium** |

## Remediation patterns

- Implementation constructor: `_disableInitializers()`.
- Deploy proxy + call initializer atomically (single factory tx).
- Mark `initialize` as `initializer`, `reinitialize` as `reinitializer(N)` with auth.
- Chain every parent's `__X_init()` in order matching inheritance.
- For clones: use a factory that deploys-and-initializes in one call.
- Test: from a fresh deploy, attempt `initialize()` twice and from a non-admin EOA — both should revert.

## False-positive notes

- Non-upgradeable contracts that just happen to use `initialize` as a name — not the same pattern.
- `Initializable` used purely as a one-shot setup guard with no proxy involved — lower severity.

## Related

- [[storage-layout]]
- [[access-control]]
- [[delegatecall-risks]]

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [omermaksutii](https://github.com/omermaksutii)
- **Source:** [omermaksutii/RugProof](https://github.com/omermaksutii/RugProof)
- **License:** MIT
- **Homepage:** https://omermaksutii.github.io/RugProof

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-omermaksutii-rugproof-initialization
- Seller: https://agentstack.voostack.com/s/omermaksutii
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
