DEV Community

Cover image for Attack anything. Risk nothing. — every exploit lands on a throwaway fork
Alex
Alex

Posted on Originally published at dolos.modelmarket.dev

Attack anything. Risk nothing. — every exploit lands on a throwaway fork

Attack anything. Risk nothing. — DOLOS throwaway fork

We already had a static auditor. We already had a federation red team.

What we did not have was a way to throw a real exploit at the deployed contracts without risking the shared Anvil that lottery and ACEX keep using.

So we built DOLOS (Δόλος — guile): a dynamic EVM attack harness. Every exploit lands on a throwaway anvil --fork-url. When the fork is torn down, none of it ever existed.

Live: dolos.modelmarket.dev · Source: github.com/alexar76/dolos (MIT) · Capability: agent.security.contract-redteam@v1


The mistake we refused to make

The obvious test pattern is: attack the live chain, then evm_revert.

On our UNI bubble that is wrong. The Anvil is shared. A revert would silently discard real activity from the lottery relayer and the ACEX trader.

So DOLOS never writes the live chain. It spawns its own fork — a copy-on-write clone of live state. Every contract, balance, and storage slot is there to attack. Funded with fake ether. Drivable as any address. Disposable.

Live DOLOS landing — the exploit crafter

Cheat code What it buys Why it is safe here
anvil --fork-url Clone of live state The clone is the target
evm_snapshot / evm_revert Total rollback between attacks The disposable thing is the fork
anvil_impersonateAccount Transact as owner / victim, no key Impossible on a real chain — that is the point
anvil_setBalance Fake gas for any address None of it outlives the fork

One sentence thesis:

Attack anything. Risk nothing. Because the target is a fork, not the bubble.

Why it is safe to attack everything


Don’t collapse the red teams

We already wrote about BASANOS (static assurance at a pinned commit) and MOMUS (HTTP / federation probes that cannot pay themselves).

DOLOS is the missing middle:

BASANOS static · DOLOS dynamic · MOMUS federation

Layer Question
BASANOS Is this Solidity sound at commit X?
DOLOS Does the deployed contract hold under a concrete attack?
MOMUS Is the live federation holey?

BASANOS can flag "any caller can write channels[<caller>]". Only actually trying the hijack on a fork — and watching the guard refuse — proves whether that flag is a real hole or a false positive.

On the live UNI contracts, DOLOS refuted that flag. It tried. The guard held. It said so.


An attack is an invariant, not a poke

Not “call a function and see what happens.”

An invariant the contract claims. A transaction sequence that would break it. The ABI comes from the Foundry build — a missing ABI is inconclusive, never a made-up interface, never an assumed pass.

Attack Invariant On real UNI contracts
unauthorized_token_mint Supply grows only through an authorized minter held
escrow_channel_hijack An open channel id cannot be reopened by another caller held
lottery_operator_bypass Only OPERATOR_ROLE may open a round / withdraw fees held

Held is a result. Not a gap.

Held. Exploited. Inconclusive.

Three first-class outcomes:

  • held (200) — the contract refused. Honest negative. Can refute a static flag.
  • exploited (561) — the invariant broke. Signed finding.
  • inconclusive (520) — could not run. Never payable. Never “safe.”

Exit code 2 on a scan means we never reached the chain. That must never read as all-clear. We learned that the hard way elsewhere in the stack — silence is not green.

Findings use the same Ed25519 Finding / Verdict / Blame shape as MOMUS, so they drop into the same store, verifier, and Treasury. Scanner key signs. A different verifier key signs the verdict. Neither is the treasury key.


The fix loop — sandbox only

On a throwaway sandbox fork (chainId 31337), a confirmed hole can drive a fix:

attack → patch → forge test gate → redeploy → re-attack.

If the legitimate-behaviour suite goes red, the fix is rejected. A canary that refuses to be exploited aborts rather than claiming a fix.

Auto-fix only on a sandbox fork

On a real immutable contract the identical finding is tagged ADVISORY and stops at the report. Auto-fix there would be a critical bug of our own.

That is why DOLOS lives in UNI — the chain is disposable, so the fix loop is free and reversible.

DolosCanary — a vault built to be broken

Proven end to end on DolosCanary: a stranger drains 5 ETH it never deposited; the fixer inserts a balance guard; forge test stays green; the redeployed contract refuses the same drain; verdict fixed.

Real UNI contracts held. There was nothing to fix. That is the correct outcome.


Run it

git clone https://github.com/alexar76/dolos
cd dolos
pip install -e '.[dev,signing]'
pytest                     # 233 tests · 96% branch coverage with Foundry

# scan: fork the live UNI anvil, run the catalog, print signed findings
python -m dolos scan --fork-url http://127.0.0.1:8545 --key data/dolos_scanner_key

# canary: full attack → fix → retest → redeploy → re-attack
python -m dolos canary --standalone
Enter fullscreen mode Exit fullscreen mode
Command 0 1 2
scan contracts held non-by-design exploit found could not run
canary / fix hole closed not closed

Optional: point DOLOS_FACTORY_FIX_URL at the Factory remediation endpoint. If the Factory is down, silent, or echoes its input, the built-in patcher takes over — never a false success.


What it is not

  • Not a mainnet attack tool. Sandbox fork only for auto-fix.
  • Not BASANOS. Static assurance is a different question.
  • Not MOMUS. Federation probes are a different surface.
  • Not insurance. Findings inform; they do not stake coverage.
  • Not “AI red team theatre.” An optional LLM cannot invent attacks or rewrite verdicts — the catalog and the fork decide.

Soft close

If you keep collapsing “audit,” “scan,” “red team,” and “insurance” into one word, you will ship a critical with a clean conscience.

We needed a layer that could actually try — and still leave the live house alone.

That layer is DOLOS.

🌐 dolos.modelmarket.dev · 📦 github.com/alexar76/dolos

If this shape is useful, a ⭐ on the repo helps more than a polite nod in the comments.

Top comments (0)