Install
$ agentstack add skill-omermaksutii-rugproof-solady-ownable-init-frontrun ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README — it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming — see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps — measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Solady Ownable initializer front-run detection
When this applies
Trigger on any of:
import {Ownable} from "solady/auth/Ownable.sol";orOwnableRoles- A contract calling
_initializeOwner(...)from a public/externalinitialize()rather than the constructor - Minimal-proxy clones (
LibClone.clone/ EIP-1167) of an Ownable implementation - Factory deployments where
create/create2andinitialize()are two separate transactions - Implementation contracts behind proxies (UUPS / transparent) using Solady Ownable
- Any
initialize/initthat is not protected by an initializer guard or atomic deploy
Detection patterns
Public init, non-atomic deploy (HIGH)
contract Vault is Ownable {
function initialize(address owner) external {
_initializeOwner(owner); // reverts on 2nd call — but ANYONE can make the 1st
}
}
// Factory:
address v = LibClone.clone(impl);
Vault(v).initialize(msg.sender); // ← separate tx: front-runnable in the mempool
Between clone and initialize, a searcher front-runs initialize(attacker). _initializeOwner succeeds for them; the legit call then reverts AlreadyInitialized. Signal: _initializeOwner reachable from an unguarded external function and deploy/init are not in one transaction.
Implementation left uninitialized (HIGH)
contract Impl is Ownable {
function initialize(address o) external { _initializeOwner(o); }
}
// Impl deployed standalone, never initialized → anyone claims it.
For UUPS, an attacker who owns the implementation can call upgradeTo/selfdestruct-style logic and brick or hijack all proxies pointing at it. Signal: Solady Ownable implementation deployed but not initialized in the same tx, and the implementation itself is callable.
Re-init via _setOwner exposure (MEDIUM-HIGH)
function _setOwner(address o) internal { ... } // Solady internal
function rescueOwner(address o) external { _setOwner(o); } // ← bypasses init guard entirely
_setOwner has no AlreadyInitialized guard; exposing it publicly defeats the one-time protection. Signal: _setOwner wrapped in an unprotected external function.
Severity rubric
| Pattern | Severity | Notes | |---|---|---| | Clone/factory with non-atomic public initialize | High | Ownership theft, mempool front-run | | Uninitialized implementation behind proxy | High | Impl hijack → proxy compromise | | _setOwner exposed externally | High | Init guard bypassed entirely | | Init gated to factory msg.sender / atomic deploy | Info | Correctly protected |
Remediation patterns
- Atomic deploy+init — initialize inside the same transaction as
clone/create, or useLibClone.cloneDeterministic+ immediate init in the factory call. - Restrict the initializer —
require(msg.sender == factory)or pass owner via clone immutable args (LibClone.clone(impl, immutableArgs)). - Lock the implementation — call
_initializeOwner(deadAddress)/_disableInitializers-equivalent in the implementation's constructor so the standalone impl can't be claimed. - Never expose
_setOwner— onlytransferOwnership(owner-gated) and the guarded_initializeOwner.
False-positive notes
- Constructor-based
_initializeOwner(non-clone deploy) is not front-runnable — Info. - Factory that deploys and initializes in one call (atomic) — not exploitable.
- Initializer gated on
msg.sender == factoryor consuming clone immutable args — safe.
Related
- [[access-control]]
- [[delegatecall-risks]] — UUPS implementation hijack
- [[centralization-risk]]
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: omermaksutii
- Source: omermaksutii/RugProof
- License: MIT
- Homepage: https://omermaksutii.github.io/RugProof
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.