Detecting suspicious on-chain behaviour before the exploit transaction
Many exploits are preceded by preparation that is visible on-chain: funding, deployment, rehearsal. A structured look at the signals, how far each can be trusted, and how to turn them into detection rules.
- Written by
- Quantix Research, Threat Intelligence
- Published
- Reading time
- 8 minutes
- Category
- Threat Intelligence
Technical analysis. Built from the public sources in the bibliography. Incident details are as reported there; no new discovery is claimed.

Contents
Post-incident reports tend to begin at the exploit transaction: the block in which value left the protocol. For the people who have to respond, that is the least useful moment. By then the transaction is final, and the only remaining work is tracing and recovery.
Many exploits, however, are not single events. They are preceded by preparation that is visible to anyone reading the chain: an address is funded, a contract is deployed, functions are rehearsed, positions are opened. This analysis looks at those stages as they are described in public incident reports and research, the signals each one produces, how reliable those signals are, and what a team can realistically do with them.
Exploits have a preparation phase
An attacker who has found a bug still has engineering work to do. The exploit has to be packaged so that it runs atomically, usually in a contract, because a sequence of separate transactions gives the protocol, arbitrage bots and other observers a chance to interfere. It has to be funded with enough gas, and often with collateral or a fee for a flash loan. It is frequently tested against a fork, and sometimes against the real deployment with small amounts.
Public mempools add a further reason to package the attack carefully. Paradigm’s widely cited essay Ethereum is a Dark Forest describes generalised front-running bots that simulate pending transactions and copy any that would be profitable, substituting their own addresses. An attacker who sends a naive exploit transaction risks being copied. Attack contracts, private submission and in-contract checks on the caller are the usual answer, and each leaves traces of its own.
Not every attack has a long preparation phase. Key compromises, as in the Ronin bridge incident, may involve nothing more on-chain than a correctly signed withdrawal. Ronin’s own community alert records that the attack took place on 23 March 2022 and was discovered on 29 March, after a user reported being unable to withdraw. That gap is a reminder that monitoring the outcome matters as much as monitoring the run-up.
The stages before T0
The stages below are a composite drawn from public incident write-ups and from the systematisation of DeFi attacks by Zhou et al. Not every incident contains every stage, and the order can vary, but the shape is common enough to plan detection around.
- Funding. A fresh address receives gas money. Attackers prefer sources that break the link to their identity: mixers, cross-chain bridges from chains with weaker analytics, or chains of intermediate addresses.
- Deployment. The funded address deploys one or more contracts, usually without verifying the source. The bytecode references the target protocol’s functions, and often a flash-loan provider’s.
- Rehearsal. Some attackers call the contract with small amounts, or call it in ways that revert, to check behaviour on the live deployment.
- Positioning. Approvals are granted, collateral is deposited, or a position is opened that the exploit will later use.
- Exploit. Usually a single transaction, often combining a flash loan, a state manipulation and an extraction.
- Laundering. Proceeds are swapped into liquid assets, bridged or deposited into mixers. The US Treasury’s August 2022 announcement on Tornado Cash, for example, stated that the mixer had been used to launder funds from the Harmony bridge and Nomad incidents. (OFAC removed the designation on 21 March 2025.)
Signals and how far to trust them
Each stage produces signals that a monitoring system can observe. The difficulty is that most of them, taken alone, also describe ordinary behaviour. Developers deploy unverified contracts daily; privacy-conscious users fund addresses through mixers; arbitrage bots call flash-loan providers constantly. The useful question for each signal is not whether it is suspicious but how much it raises the probability of an attack when combined with others.
| Signal | Stage | Specificity | Common benign explanation |
|---|---|---|---|
| Fresh address funded via a mixer | Funding | Low alone | Privacy-conscious users and developers |
| Unverified contract whose bytecode embeds the protocol’s selectors | Deployment | Medium | Integrations, bots and aggregators |
| Same contract also embeds flash-loan entry points | Deployment | Medium to high | Arbitrage and liquidation bots |
| Reverted calls from that contract to the protocol | Rehearsal | Medium | Bots probing for opportunities |
| Calls to admin or rarely used functions from new addresses | Rehearsal | High | Mistaken calls by users |
| Large deviation in a price or exchange rate the protocol reads | Exploit | High | Genuine market moves |
| Outflow far above historical daily volume | Exploit | High | Large legitimate withdrawals |
| Proceeds routed to a bridge or mixer within minutes | Laundering | High (after the fact) | Rarely benign at that speed |
Two patterns stand out. Signals become more specific closer to the exploit, and the time available to act shrinks at the same rate. And the most informative early signal is usually a combination: a contract from a new, mixer-funded address that references both a flash-loan provider and the protocol’s own functions is far more interesting than any one of those facts.
From signals to detection rules
A detection rule turns a combination of signals into an alert. The sketch below scores newly deployed contracts. It looks for the four-byte selectors of watched functions inside the runtime bytecode. A contract that calls a function normally pushes that function’s selector onto the stack with the PUSH4 opcode (0x63), so the selector appears in the bytecode immediately after that byte. The heuristic can be evaded with computed selectors, and it can match by coincidence, which is why it contributes to a score rather than raising an alert on its own.
// Illustrative scoring of a newly deployed contract. Weights and thresholds are// examples to be tuned against your own history of benign deployments.import { toFunctionSelector } from 'viem' type Deployment = { runtimeBytecode: `0x${string}` sourceVerified: boolean deployerFirstSeenBlocksAgo: number deployerFundedVia: 'mixer' | 'bridge' | 'exchange' | 'contract' | 'eoa'} // Functions of the protocol you defend, plus generic flash-loan entry points.const WATCHED = [ 'flashLoan(address,address,uint256,bytes)', // ERC-3156 lender 'liquidate(address,address,uint256)', // your protocol (example) 'redeem(uint256,address,address)', // ERC-4626 vault].map((sig) => ({ sig, selector: toFunctionSelector(sig).slice(2) })) export function scoreDeployment(d: Deployment) { const code = d.runtimeBytecode.toLowerCase() // A contract that calls a function usually embeds its selector as PUSH4 (0x63). const hits = WATCHED.filter((w) => code.includes('63' + w.selector)) let score = 0 const reasons: string[] = [] if (hits.length >= 2) { score += 40; reasons.push(`calls ${hits.map((h) => h.sig).join(', ')}`) } if (!d.sourceVerified) { score += 15; reasons.push('source not verified') } if (d.deployerFirstSeenBlocksAgo < 7_200) { score += 15; reasons.push('deployer is less than ~1 day old') } if (d.deployerFundedVia === 'mixer') { score += 25; reasons.push('deployer funded through a mixer') } return { score, reasons, alert: score >= 70 } // alert → human triage, not an automatic pause}In practice, teams run several such rules and route the combined result to a person. Decentralised monitoring networks such as Forta provide infrastructure for running detection logic against every block, and protocol-run monitors do the same against a narrower scope. Either way, the rules are only as good as the protocol-specific knowledge behind them: which functions matter, which values must not move, and what normal looks like.
False positives and the cost of acting
Every rule has a false-positive rate, and every response has a cost. Pausing a lending market interrupts liquidations, which can create bad debt of its own. Pausing a bridge strands users mid-transfer. A team that pauses on every alert will soon stop being taken seriously by its users, and one that never pauses gains nothing from detection.
A workable approach separates three levels. Low-confidence alerts are logged and reviewed in working hours. Medium-confidence alerts page an on-call responder with the context needed to judge them in minutes: the deployer’s funding path, a decoded view of the contract’s calls, and a simulation of what the contract does against the current state. Only high-confidence alerts, typically those based on the protocol’s own invariants breaking, trigger an automated action, and only actions that are cheap to reverse.
What a response can do in minutes
Detection is useful only if something can be done with it. The options depend on controls the protocol built in advance; none can be added during an incident.
- Pause guardians. A narrowly scoped role that can pause specific functions, held by a key or multisig that can act quickly, with unpausing reserved for slower governance.
- Rate limits and withdrawal delays. Caps on outflow per block or per hour turn a total loss into a partial one and buy time for a human decision. They are especially valuable on bridges, where outflows are easy to measure.
- Simulation before submission. If a suspicious contract is found before it is used, simulating its likely calls against current state shows whether it is a threat and which function to protect.
- Coordination. Pre-agreed contacts at stablecoin issuers, bridges and exchanges can freeze or flag proceeds during laundering. This does not prevent the exploit, but it can reduce the loss.
The recorded investigations in Security Monitoring follow incidents through these stages, and the compromised upgrade administrator case study shows how a privileged-call alert fits into a response plan.
Limits of pre-attack detection
Pre-attack detection is a probabilistic aid, not a defence. A determined attacker can deploy and execute in the same transaction, use a contract created through a factory, compute selectors at runtime, submit through private order flow so the exploit is never visible in a public mempool, and fund the address from a source that looks ordinary. Key compromises may produce no preparation on-chain at all.
What detection can do is raise the cost of an attack, catch the less careful attackers, and shorten the time between an exploit and a response. That last benefit is underrated. The six days between the Ronin exploit and its discovery were not a failure of pre-attack detection, which could not have seen a validly signed withdrawal coming, but of outcome monitoring, which could have.
Conclusions
The run-up to many exploits is visible on-chain, and its stages produce signals that are individually weak and collectively informative. Signals grow more specific as the exploit approaches, while the time to act shrinks. Detection rules are most reliable when they combine attacker-side signals with the protocol’s own invariants, and most useful when the protocol has built controls that a responder can use within minutes.
Monitoring the protocol’s state, not only its adversaries, is the part of detection that cannot be evaded by a careful attacker, and it is the part most often missing.
Recommendations
Protocol teams
- Write down the five to ten values that must never move abruptly (total assets, share price, outflow per block) and alert on each.
- Build scoped pause and rate-limit controls before launch, with a documented decision tree for when to use them.
- Maintain a list of your own function selectors and watch for new contracts that embed them together with flash-loan entry points.
Monitoring and response
- Score combinations of signals rather than alerting on any single one; record every alert outcome to tune thresholds.
- Give on-call responders a one-page context for each alert: funding path, decoded calls and a simulation result.
- Pre-arrange contacts with stablecoin issuers, bridges and exchanges for the laundering stage.
Reviewers
- Check that monitoring covers outcome invariants, not only known attack patterns.
- Ask how long an unauthorised but correctly signed withdrawal would go unnoticed, and what would notice it.
Bibliography
Primary sources: standards, official documentation, incident reports and papers.
- 1Community Alert: Ronin Validators Compromised(opens in a new tab)Ronin (Sky Mavis), March 2022
- 2Ethereum is a Dark Forest(opens in a new tab)Dan Robinson and Georgios Konstantopoulos, Paradigm, 2020
- 3SoK: Decentralized Finance (DeFi) Attacks(opens in a new tab)Zhou et al., arXiv:2208.13035
- 4U.S. Treasury Sanctions Notorious Virtual Currency Mixer Tornado Cash(opens in a new tab)U.S. Department of the Treasury, 8 August 2022
- 5A Legal Whirlwind Settles: Treasury Lifts Sanctions on Tornado Cash(opens in a new tab)Venable LLP, 8 April 2025
- 6Forta Network documentation(opens in a new tab)Forta
- 7Maximal extractable value (MEV)(opens in a new tab)ethereum.org
Applied on this site
Assessments, case studies and tools that apply this publication.




