The exploit executed on a mainnet fork and you get the working PoC. Criticals carry this burden; lower tiers stand on a concrete attack path tied to a broken invariant.
evidence: fork exploit · 142.8 ETH drained
The methodology
Every contract is examined against a fixed taxonomy of exploitable bug classes, each finding is graded on impact and likelihood, and no verdict ships until the code itself justifies it — kept with a working exploit, or killed by a cited line.
Each class is a checklist of exploit patterns, not a keyword grep. We map the system first, then probe each class against your actual call graph and state flow.
Single-function, cross-function, and cross-contract reentrant callbacks; ERC-777 / ERC-721 receiver hooks; read-only reentrancy against view-priced math.
surfaces: vault withdraw / claim paths, router callbacks
Spot price read as an oracle, flash-loan-inflated reserves, stale or uninitialized feeds, missing staleness / heartbeat checks.
surfaces: liquidation math, collateral valuation
Unprotected admin entrypoints, role rotation that bypasses a timelock, uninitialized proxies, missing two-step ownership, guardian escalation.
surfaces: upgrade paths, role managers
Total-supply ≠ sum-of-balances, share / asset rounding to the protocol's loss, fee math under / overflow, queue state vs. token balance divergence.
surfaces: ERC-4626 vaults, fee accumulators
Ignored transfer / call return, low-level call success not checked, gas-griefing on external hooks, unbounded loops over attacker-controlled arrays.
surfaces: token integrations, payout loops
Missing zero-address / zero-amount guards, out-of-order state transitions, signature replay or missing nonce, deadline / slippage omissions.
surfaces: permit flows, multi-step settlement
Novel, bespoke attack paths and economic or game-theoretic design flaws — incentive misalignment, governance attacks, MEV strategy — need human judgment. We map the surface and flag the questions; we don't claim to design your tokenomics.
Where AI ends and humans begin →Severity is impact × likelihood, judged against your system's invariants — not the model's gut feeling. Criticals carry a higher burden of proof than lows.
Direct, unconditional loss of user funds or protocol insolvency.
Burden: A working exploit on a mainnet fork.
no privilege required · core invariant broken
Fund loss or protocol takeover under realistic preconditions — a specific role, a specific market state.
Burden: A concrete attack path tied to an invariant.
narrow precondition · privileged actor
Value at risk under narrow conditions, or a broken invariant with bounded harm.
Burden: A reproducible path with a defined blast radius.
harm bounded · external precondition
Defensive-coding gaps and best-practice deviations with no direct exploit path today.
Burden: A demonstrated deviation, not an exploit.
no live exploit · hardening only
Observations, gas optimizations, and hardening notes.
Burden: An argued recommendation.
no value at risk
The burden of proof in the third column is not a label — it's the bar the validator has to clear before the finding ships. That's the trial below.
Independent AI models propose findings. We distrust every one of them. A finding is
kept only when it's grounded in your invariants — and for criticals, proven with a
working fork exploit. It's killed only when the validator can cite the exact line that
defeats the exact attack step. If neither holds, it stays in front of a human as
needs_manual — never silently dropped.
The exploit executed on a mainnet fork and you get the working PoC. Criticals carry this burden; lower tiers stand on a concrete attack path tied to a broken invariant.
evidence: fork exploit · 142.8 ETH drained
The validator quotes the defeating line and names the attack step it defeats. A false positive is dropped only when one reason from a closed taxonomy holds:
guard_exists · Vault.sol:142
No line defeats it and no exploit lands. The finding stays visible to a human, flagged for review — it is never hidden to make the report look clean.
disposition: awaiting human review
The refutation taxonomy is closed on purpose. The validator cannot invent a new reason to dismiss a finding — it has to fit one of these six, anchored to a line in your code, or the finding survives to a human.
Before hunting bugs, Guardix extracts your system's invariants, assumptions, and design decisions as first-class artifacts. A finding only stands if it breaks one — that's what keeps the report grounded instead of guessing, and it's the same invariant set the validator cites when it kills a finding.
Each invariant carries a threat if broken, so a finding's severity is read off the system's own design, not assigned by feel.
Total supply must equal sum of individual balances at all times
Threat if broken
Direct loss of depositor funds
Queue state transitions must be monotonic: pending → processing → done
Threat if broken
Double-processing of withdrawals
Oracle price feeds assumed fresh within 1-hour staleness window
Threat if broken
Incorrect liquidation at stale prices
Admin role changes cannot bypass timelock constraints
Threat if broken
Unauthorized privilege escalation
The methodology ends in a document you can take to your team, your investors, or your own next review. Every finding carries its own evidence — this is what each one ships with.
See how scans are versioned and shared →Connect a GitHub repository, lock the commit, and get findings graded against your invariants — kept with a working exploit, killed by a cited line, or held for a human.