Revoker Ethereum Sepolia

Autonomous on-chain security agent · built on KeeperHub

The agent that lands the revoke before the drainer moves.

Token approvals are the most common wallet-drain vector, and every tool built for them is read-only: it tells you an approval is risky, and stops there. Revoker acts. The moment a threat rule fires it executes approve(spender, 0) through KeeperHub, with no human in the loop.

Every number on this page links to a transaction you can open.

12.95s median detect → revoke
(p95 24.88s)
25/25 benchmark cycles
succeeded
46,482 gas per revoke (p50)
sponsored 25/25

Proof of execution

A real drain, really stopped.

The full cycle, executed on Ethereum Sepolia. Three transactions, in order. Open each one.

  1. The trap

    Victim grants unlimited approval

    The everyday act that arms every drain: approve(spender, MAX_UINT256) to a spender contract. Allowance jumps to 1.157e77 — effectively infinite.

    0xfe39a5f4…017482 allowance = 1.157e77
  2. The response

    Revoker fires — no human involved

    Two rules trip — unlimited-to-unverified and denylisted. Revoker executes approve(spender, 0) through KeeperHub's atomic check-and-execute, with no human in the loop.

    0x325f6d51…7e09f9 allowance = 0
  3. The verdict

    The drainer fires anyway

    The drain transaction succeeded. It did not revert. It was not blocked. It ran exactly as its author intended — and it found nothing to take, because the approval was already gone.

    0xe127f3d2…a1a303 drained: 0

Step 3 is the whole story. Revoker doesn't intercept the attack — it makes the attack find an empty room.

took 0

victim's balance unchanged: 10,000 mUSDC across the whole sequence

Reading the explorer links: KeeperHub executes through a sponsored relay, so the from address is KeeperHub's relayer — not the signer. The flow is relayer 0x809d…0444 → forwarder 0x5af5…f07d → Turnkey account 0x5E2e…bab7. The signer appears in the calldata; this is expected, not an anomaly.

Don't take our word for it

Check the allowance yourself, right now.

One cast call against a public RPC. No credentials, no account, no trust in this page required.

cast call 0x4facb5FD1682c4449cAD42b7590861f7eD5c88Cb \
  "allowance(address,address)(uint256)" \
  0x5E2e5Fd3aD7fDC9B94482930db8b5F45E439bab7 \
  0x8eBf8540EdE8e40CD94825C418758d4029D8892e \
  --rpc-url https://ethereum-sepolia-rpc.publicnode.com

Expected output: 0 — the allowance Revoker zeroed is still zero.

The technical differentiator

A revoke that can't be front-run.

Most agents read state, decide, then write. That gap between deciding and acting is exactly what a mempool-watching drainer needs.

read-then-write a typical agent

read allowance→ 1.157e77
front-run window The drainer sees the pending revoke in the mempool and slips a transferFrom in here — before the revoke lands.
approve(spender, 0)
Decides at time T, acts at T+n. The window is the attack surface.

check-and-execute Revoker, via KeeperHub

read allowancelive chain state
approve(spender, 0)
one atomic server-side operation
Same two steps, no gap between them. Nothing to front-run.

The condition is evaluated against the live chain, not a value this process passed in. On the reference run KeeperHub reported, at execution time:

observedValue: 115792089237316195423570985008687907853269984665640564039457584007913129639935
= 2256 − 1 — the MAX_UINT256 allowance, re-read server-side.

No key to steal. Signing happens inside a Turnkey enclave via KeeperHub — the agent process never holds a private key. An autonomous agent with a hot key is a liability; one that can only ask a policy-bound signer to act is not.

Detection

Three rules. No model.

Concrete, auditable threat conditions. Every firing carries its evidence into the audit trail, so a revoke can be justified after the fact.

unlimited-to-unverified

A MAX_UINT256 allowance granted to a contract whose source is unreadable — infinite trust in code nobody can inspect.

signal: KeeperHub ABI resolution, live

young-spender

The spender contract was deployed less than 7 days ago. Fresh contracts holding spend rights are a classic drain setup.

signal: eth_getCode + binary search

denylisted

The spender is on the known-bad list. No further debate — a confirmed bad actor with an open allowance gets revoked.

signal: data/denylist.json

Any one rule firing is sufficient. These are independent signals of different kinds, not weighted terms in a score — requiring consensus would mean ignoring a confirmed deny-list hit because the contract happened to be verified. And deliberately not an ML risk model: an agent that moves funds on an opaque score is not auditable, and “the model said so” is not a defence when it is wrong.

Benchmark

Measured, not claimed.

25 full detect→revoke cycles against live Sepolia, each one confirmed by reading the chain — not by trusting the execution report.

Latency distribution over 25 cycles
Metricp50p95minmax
response — detection → revoke confirmed 12.95s24.88s10.33s24.95s
exposure — threat live → revoke confirmed 13.38s25.01s10.47s25.28s
cycles: 25/25 succeeded gas per revoke: 46,482 (p50 = p95) sponsored: 25/25
Response time per cycle — every bar is a real transaction; click one. Cycles 10–13 hit a slow block-inclusion window (amber).

What these numbers do not include. The benchmark triggers detection immediately rather than waiting for the poll timer, so a deployment polling every pollIntervalMs adds an average of pollIntervalMs/2 on top.

The p95 is nearly double the p50 because four consecutive cycles hit a slow block-inclusion window — that variance is the network's, not the agent's, which is exactly why this is reported as a distribution instead of a headline number. Full per-cycle table: BENCHMARK.md in the repo.

Integration

KeeperHub is the engine, not decoration.

10 distinct API surfaces 12 application call sites 86 tests 3 threat rules

Remove KeeperHub and Revoker needs seven separate systems: a transaction relayer, a congestion-aware gas oracle, an MEV-protected submission route, a confirmation poller, an action-discovery layer, an ABI resolution service, and an audit-log pipeline — plus a custody solution. The sharpest dependency isn't convenience; it's that the atomic check-and-execute and the enclave-held key are things a standalone script cannot honestly replicate.

KeeperHub API surfaces used by Revoker
SurfaceUsed for
POST /api/execute/check-and-executethe atomic revoke
POST /api/execute/contract-callcontract writes, arming the demo approval
POST /api/execute/transfernative transfers
GET /api/execute/{id}/statusconfirmation, gas, sponsorship, audit record
GET /api/chainsnetwork + explorer resolution
GET /api/chains/{id}/abisource-verification signal for rule 1
GET /api/user/walletsigner identity assertion
GET /api/user/wallet/balancestoken discovery (curated registry)
simulate: truepre-flight dry runs before spending gas
Idempotency-Keysafe retries without double-execution

Scope

Known limits, stated plainly.

A security tool that hides its blind spots is part of the problem. These are Revoker's, on the record.

  1. Sepolia testnet only

    The mainnet path is documented, not executed. No real funds were risked producing any number on this page.

  2. Token discovery is watchlist-scoped

    No public RPC serves an address-less eth_getLogs over a useful block range. Revoker protects the tokens it is told to watch, rather than implying coverage it does not have. Production would resolve the set from an indexer.

  3. young-spender needs an archive RPC

    Without one it returns INDETERMINATE and names the remedy — loudly — instead of reporting “safe”. A threat rule that silently degrades into a rubber stamp is worse than one that admits it cannot see.

  4. The threat model is narrow on purpose

    A spender that is verified, aged, and absent from the deny-list trips nothing. That case is out of scope, not silently mishandled.

  5. The /verify dashboard runs locally

    A continuous watcher cannot be a serverless function, so the live dashboard is served from the same long-lived process that does the watching.

Demo

Watch the full cycle.

Demo video — not yet published

The recorded run of the exact cycle proven above: seed the threat, watch Revoker detect and revoke it, then verify on-chain. This section will hold the embed.