example-fork-detection
TEMPLATE — replace with the description of your rule. Should activate on the specific code patterns your fork has. Activate on…
Detect vote-escrow (ve) governance manipulation — Curve veCRV, Velodrome/Aerodrome veNFT, Balancer veBAL, and gauge/bribe markets. Activate whenever code reads voting power from a lock balance, computes gauge weights, distributes bribes/incentives, snapshots votes, or lets locks
Claude Code
$ npx -y skills add omermaksutii/RugProof --skill ve-lock-governance --agent claude-code
Codex
$ npx skills add omermaksutii/RugProof --skill ve-lock-governance -a codex -y
Cursor
$ npx skills add omermaksutii/RugProof --skill ve-lock-governance -a cursor -y
Gemini CLI
$ npx skills add omermaksutii/RugProof --skill ve-lock-governance -a gemini-cli -y
GitHub Copilot
$ npx skills add omermaksutii/RugProof --skill ve-lock-governance -a github-copilot -y
OpenCode
$ npx skills add omermaksutii/RugProof --skill ve-lock-governance -a opencode -y
Windsurf
$ npx skills add omermaksutii/RugProof --skill ve-lock-governance -a windsurf -y
name: ve-lock-governance description: Detect vote-escrow (ve) governance manipulation — Curve veCRV, Velodrome/Aerodrome veNFT, Balancer veBAL, and gauge/bribe markets. Activate whenever code reads voting power from a lock balance, computes gauge weights, distributes bribes/incentives, snapshots votes, or lets locks be created/extended/merged/split/transferred — especially when vote weight is read live rather than at proposal-creation block.
Trigger on any of:
function castVote(uint256 proposalId, bool support) external {
uint256 weight = ve.balanceOf(msg.sender); // ← read NOW, not at proposal start
proposals[proposalId].votes[support] += weight;
}**Signal:** voting power read at vote time enables flash-lock: borrow, lock, vote, then exit if `withdraw` allowed same block, or vote with freshly minted power. Snapshot at proposal-creation block (`getPastVotes`).
Last-block vote stuffing before the weekly checkpoint redirects emissions. If gauge weights are read at the instant of `checkpoint_gauge` with no time-weighting, a single-block max vote captures a full epoch of emissions (Curve gauge-war griefing class). **Signal:** emission direction determined by instantaneous weight, not a bias-weighted moving average.
function merge(uint256 from, uint256 to) external { ... } // does it clear `voted[from]`?**Signal:** Velodrome-class finding — `split`/`merge` not resetting the per-NFT `voted` flag or per-epoch vote accounting lets one underlying balance vote twice in an epoch. Also check `transferFrom` mid-epoch carrying voting power to a non-voted recipient.
Linear-decay `bias - slope * (t - t0)` underflowing past expiry, or assuming `MAXTIME` lock when `unlock_time` was rounded down to the week. Off-by-one-week rounding inflates or deflates power at epoch boundaries.
Claiming bribes for an epoch you voted in, then re-voting next epoch with the same balance, or claiming on a transferred veNFT — verify bribe accounting is keyed to (tokenId, epoch) and frozen at the vote.
| Pattern | Severity | Notes | |---|---|---| | Flash-lock vote with same-block exit | **Critical** | Direct governance capture | | Live (un-snapshotted) vote weight | **High** | Borrowed-power voting | | merge/split/transfer double-vote | **High** | Velodrome-class veNFT bug | | Last-block gauge stuffing | **High** | Emission theft per epoch | | Decay/rounding precision at week boundary | **Medium** | Bounded mis-weighting | | Bribe claim re-use across epochs | **Medium** | Incentive leakage |
1. **Snapshot voting power** at proposal-creation block via `ERC20Votes.getPastVotes` / checkpoint history — never `balanceOf` at vote time. 2. **Time-bias gauge weights** (Curve's `points_weight` slope/bias with future-epoch bias) so a single block cannot dominate an epoch. 3. **Reset per-NFT vote state on `merge`/`split`/`transfer`** and forbid transfer of a veNFT that has voted in the current epoch (Velodrome `voted` lock). 4. **Key bribe accounting to (tokenId, epoch)** and freeze the balance used at vote time. 5. **Disallow withdraw before unlock** and round `unlock_time` consistently (floor to week) everywhere.
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…