example-fork-detection
TEMPLATE — replace with the description of your rule. Should activate on the specific code patterns your fork has. Activate on…
Detect ERC-4626 inflation/donation attacks — first depositor share-price manipulation, naive convertToShares math, missing virtual-shares defense. Activate on any ERC-4626 vault implementation, share/asset math, `convertToShares`, `convertToAssets`, `previewDeposit`,
Claude Code
$ npx -y skills add omermaksutii/RugProof --skill erc4626-inflation --agent claude-code
Codex
$ npx skills add omermaksutii/RugProof --skill erc4626-inflation -a codex -y
Cursor
$ npx skills add omermaksutii/RugProof --skill erc4626-inflation -a cursor -y
Gemini CLI
$ npx skills add omermaksutii/RugProof --skill erc4626-inflation -a gemini-cli -y
GitHub Copilot
$ npx skills add omermaksutii/RugProof --skill erc4626-inflation -a github-copilot -y
OpenCode
$ npx skills add omermaksutii/RugProof --skill erc4626-inflation -a opencode -y
Windsurf
$ npx skills add omermaksutii/RugProof --skill erc4626-inflation -a windsurf -y
name: erc4626-inflation description: Detect ERC-4626 inflation/donation attacks — first depositor share-price manipulation, naive convertToShares math, missing virtual-shares defense. Activate on any ERC-4626 vault implementation, share/asset math, `convertToShares`, `convertToAssets`, `previewDeposit`, `previewMint`, `totalAssets`, `_decimalsOffset`.
The classic "donation" or "inflation" attack on share-based vaults. First depositor mints 1 wei share for 1 wei of asset → share price = 1. Attacker then donates large amount directly to the vault (bypassing deposit) → totalAssets balloons → share price massively inflated → next depositor rounds shares to 0.
Has caused real, public losses across many forks of naive ERC-4626.
function convertToShares(uint256 assets) public view returns (uint256) {
if (totalSupply() == 0) return assets;
return assets * totalSupply() / totalAssets();
}First deposit: 1 share for 1 asset. Donation: totalAssets += 1e30. Next depositor's 1 asset → `1 * 1 / 1e30 = 0` shares. Funds lost.
Defense: OZ ERC4626 v4.9+ uses `_decimalsOffset()` to mint "virtual" shares:
function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual override returns (uint256) {
return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding);
}This adds N virtual shares (typically 10**6 — 6 decimals offset) that nobody owns. Donations have far less leverage.
Alternative defense: mint a fixed amount (e.g. 1000 shares) to `address(0)` or `address(this)` on first deposit. Locks initial donation impact.
If first depositor deposits a large amount (say, 10K USDC), donation impact is bounded.
Some impls require admin to seed vault before allowing deposits. Acceptable defense; centralized but bounded.
ERC-4626 spec: rounding favors the vault.
Reversed direction = attacker can extract value via rounding.
Vaults holding rebasing tokens (stETH, etc.) — totalAssets() increases via rebase, not via internal accounting. Attack vectors similar but defenseless naive impl.
Naive implementation that always sums the actual balance is the vulnerable shape. Better: track internally and rebase carefully.
| Pattern | Severity | |---|---| | Naive share math + no virtual shares + no dead-shares + no min-deposit | **Critical** | | Naive math + minimum first deposit but very low | **High** | | Asymmetric round direction (favoring depositor) | **High** | | `totalAssets() = balanceOf(this)` with rebasing token, no defense | **High** | | Virtual shares of 0 decimals offset on 18-decimal asset (insufficient) | **High** | | Dead-shares but very small (e.g. 1 wei) | **High** | | OZ ERC4626 v4.9+ with default offset (6) | **Info** *(canonical defense)* |
Rugproof your code before someone else does. 🌐 Live site: omermaksutii.github.io/RugProof 📦 Latest: v1.0.0 — 45 commands · 23 agents · 45 skills · 13 MCP servers · tested, offline-first, with rule packs, a benchmark, non-EVM coverage, and post-deploy
TEMPLATE — replace with the description of your rule. Should activate on the specific code patterns your fork has. Activate on…
Detect unsafe assumptions about Solady's gas-optimized ERC20/ERC2612 permit and DN404 metadata. Solady's ERC20 uses custom…
Detect front-runnable ownership initialization in Solady Ownable / OwnableRoles. Solady's `_initializeOwner` is a guarded…
Detect Solady SafeTransferLib calls that assume the token has code. SafeTransferLib.safeTransfer/safeTransferFrom/safeApprove…
Detect Uniswap V4 hooks that fail to settle currency deltas with the PoolManager. Every credit/debit a hook creates…
Detect Uniswap V4 hooks whose address-encoded permission flags don't match the callbacks the hook actually implements. In V4 the…
Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…
Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys)…
Clean and finalize authorized natural-language text intended for readers by auditing suspicious invisible Unicode and rewriting…