A replay attack takes a transaction that was already signed and valid in one place, and rebroadcasts it somewhere it was never meant to run. The signature is real, so the receiving network accepts it — even though the owner never authorized that second transaction.
On blockchains, this usually happens after a hard fork splits one network into two that share the same history and the same account keys. A transaction you sign on one chain can be copied and replayed on the other, moving your funds a second time without your consent.
The fix most EVM networks rely on is a chain ID: a unique number baked into the signature that ties a transaction to exactly one network. Get the chain ID wrong and the signature no longer matches, so the replayed transaction is rejected. The rest of this guide covers how replay attacks actually work, the real case that forced Ethereum to solve this, and where chain ID stops short.
What Is a Replay Attack?

A replay attack is the reuse of a legitimate, already-signed message to trigger an action a second time. The attacker doesn’t forge or crack anything — they capture a valid transaction and resubmit it, relying on the system to treat the authentic signature as authorization.
The idea predates crypto. In ordinary network security, an attacker might capture an encrypted login packet and resend it to gain access, without ever decrypting the password inside. Anti-replay protection is the general class of defenses against exactly this: making each signed message usable only once, in only one context.
On a blockchain, the “message” is a signed transaction. It carries a sender, a recipient, an amount, and a cryptographic signature proving the account owner approved it. Nothing in a bare transaction says which network it belongs to — and that gap is what a replay attack exploits.
Why Blockchains Are Vulnerable to Replayed Transactions
The problem shows up when two blockchains share the same transaction history and the same account structure. That’s not a rare coincidence — it’s the normal result of a contentious hard fork.
When a network hard-forks into two chains, every account and its balance exists on both sides at the moment of the split. Your private key controls the same address on each chain. A transaction signed for one is cryptographically valid on the other, because both inherited identical rules and identical keys.
Here’s why that matters. Suppose you send 10 coins to an exchange on the new chain after a fork. If both chains still validate transactions the same way, someone watching the network can grab that signed transaction and broadcast it on the old chain too. Now 10 coins move on both chains — and you only meant to send once.
Early blockchains had no built-in way to distinguish one chain’s transactions from another’s. Without a network identifier inside the signed data, a wallet and a node have no way to tell that a transaction was meant for a different chain entirely.
The Ethereum and Ethereum Classic Split
The clearest real-world example is the 2016 event that created Ethereum Classic. It turned replay attacks from a theoretical risk into an active problem that drained real funds.
In June 2016, an attacker exploited a reentrancy bug in The DAO, a large investment contract on Ethereum, and siphoned off more than 3.6 million ETH — roughly $60–70 million at the time — out of the 12.7 million ETH the contract held, according to the Corporate Finance Institute. The Ethereum community voted to reverse the theft with a hard fork.
On 20 July 2016, that fork took effect at block 1,920,000, rolling back the hacked transactions on the new chain. Not everyone agreed with rewriting history, so the original unforked chain survived as Ethereum Classic. Two chains now existed, sharing every address and balance from before the split.
Because both networks ran the same client software with the same validation rules, the fork created a live replay attack: a transaction broadcast on one network was valid on the other. People lost funds when transactions they made on one chain were replayed on the other without permission.
Ethereum Classic didn’t fully resolve transaction replay attacks until 13 January 2017, after ECIP-1011 proposed a chain ID mechanism to separate the two networks. The gap between the split and the fix is a good measure of how disruptive unprotected forks can be.
How Chain ID Prevents Replay Attacks
A chain ID is a unique integer that identifies a specific blockchain network to wallets, nodes, and signing software. Ethereum mainnet is chain ID 1; Ethereum Classic is chain ID 61. Including that number inside the signed transaction is what makes a signature valid on one network and invalid on every other.
This became standard on Ethereum through EIP-155, authored by Vitalik Buterin and activated in the Spurious Dragon hard fork at block 2,675,000. Before EIP-155, a signed transaction contained six fields and said nothing about its network. EIP-155 added the chain ID into the data that gets signed.
How the Signature Encodes the Chain ID
EIP-155 works by folding the chain ID into the signature’s v value — the recovery identifier that helps reconstruct the signer’s public key. After the fork, v is set to {0,1} + CHAIN_ID * 2 + 35, where the {0,1} part is the parity bit from the signature itself.
The practical effect is that the chain ID is now part of what the signature commits to. A transaction signed with chain ID 1 produces a v value that only matches on Ethereum mainnet. Replay it on a chain expecting a different ID, and the signature check fails — the node rejects it before it ever reaches a block.
Transactions signed the old pre-155 way, with a v of 27 or 28, still validate for backward compatibility. But any wallet or library signing transactions today includes the chain ID by default.
Checking a Network’s Chain ID
Applications read the chain ID through the eth_chainId JSON-RPC method, which returns the identifier of the network a node is connected to. Wallets use it to confirm they’re signing for the right chain, and to warn you when a dApp asks you to switch networks.
A short list of common EVM chain IDs:
| Chain ID | Network |
|---|---|
| 1 | Ethereum mainnet |
| 56 | BNB Smart Chain |
| 137 | Polygon |
| 42161 | Arbitrum One |
| 10 | Optimism |
| 61 | Ethereum Classic |
| 11155111 | Sepolia testnet |
If you connect an application to a chain through an RPC endpoint, eth_chainId is one of the first Ethereum JSON-RPC methods worth calling to confirm you’re pointed at the network you think you are. A provider such as NOWNodes exposes it on supported EVM networks alongside standard RPC access.
Replay Attacks Inside Smart Contracts
Chain ID handles replay between networks, but there’s a second kind of replay that happens within a single chain — and chain ID alone doesn’t stop it. This one lives at the smart contract level.

Many contracts accept signed messages instead of on-chain transactions. Gasless transfers, meta-transactions, and off-chain approvals all work by having a user sign a message that someone else submits later. If the contract doesn’t track which messages it has already processed, an attacker can submit the same signed message again — a signature replay.
The distinction matters because the signed data here isn’t a standard transaction with a chain ID in its v value. It’s an arbitrary message the contract interprets. Protecting it is the contract developer’s job, not the protocol’s.
Two mechanisms do most of the work:
- Nonces. A per-user counter stored in the contract. Each signed message includes the expected nonce, and the contract rejects any message whose nonce it has already used. This makes every signature single-use.
- Domain separators. The EIP-712 standard binds a signed message to a specific contract, chain ID, and version through a hashed “domain.” A signature meant for one contract won’t verify on another, even on the same network.
Without these, a working signature can be replayed until the account is drained. With them, each message is tied to one contract, one chain, and one use. Developers building this kind of flow should treat nonce handling as a core requirement and confirm it during a security audit, not an afterthought.
Where Chain ID Protection Stops
Chain ID is reliable, but it only covers what it’s designed to cover. Knowing its limits prevents a false sense of safety.
It protects against cross-chain transaction replay, full stop. It does nothing about signature replay inside a contract, which needs nonces and domain separators as shown above. A chain with a properly assigned, unique chain ID is safe from transaction replay with a sister chain — but a fork that reuses an existing chain ID, or neglects to set one, reopens the hole.
There’s also the human layer. Chain ID stops a replayed transaction from validating, but it can’t stop you from signing a malicious transaction in the first place, or approving a token allowance you didn’t understand. Previewing what a transaction will do before signing — the same check modern wallets run automatically — covers a different class of risk that replay protection was never meant to address.
For teams moving assets between networks, replay protection is one guarantee among several. A cross-chain bridge has its own trust assumptions that have nothing to do with chain ID, and those are often the larger exposure.
Conclusion
A replay attack succeeds when a signature valid in one context gets accepted in another. On blockchains, that context is usually the network, and the damage usually follows a hard fork that leaves two chains sharing keys and history — exactly what happened to Ethereum and Ethereum Classic in 2016.
Chain ID closes the main gap by binding each signed transaction to a single network through EIP-155, so a transaction meant for Ethereum mainnet can’t validate on any other EVM chain. It’s a small number with an outsized effect, and it’s why modern forks rarely repeat the 2016 mess.
The part chain ID doesn’t cover — signature replay inside contracts — falls to developers, who handle it with nonces and EIP-712 domain separators. Reliable network access matters here too: whether you’re checking a chain ID with eth_chainId or testing a contract’s replay handling, you need a node that answers correctly for the network you’re actually on. That foundation is what makes every layer above it trustworthy.
FAQ
What happens to a transaction if the chain ID is wrong?
The node rejects it. Because the chain ID is folded into the signature under EIP-155, a mismatch means the signature no longer recovers a valid signer for that network, so the transaction fails validation and never reaches a block.
Is a replay attack the same as a double-spend?
No. A double-spend tries to spend the same funds twice on one chain, usually by racing or reorganizing transactions. A replay attack reuses one genuinely authorized transaction in a second context, most often on a different chain after a fork.
Do all blockchains use chain IDs?
No — chain IDs are an EVM concept standardized for Ethereum and compatible networks. Non-EVM chains use their own replay-protection methods, and some early or poorly configured forks have shipped without any, which is what makes unprotected forks risky.
Can replay attacks still happen on Ethereum today?
Transaction-level replay between Ethereum and other EVM chains is prevented by EIP-155, since every network has a distinct chain ID. The remaining risk is signature replay inside smart contracts, which depends on each contract implementing nonces and domain separators correctly.
How do I find a network’s chain ID before connecting?
Call the eth_chainId method against an RPC endpoint for that network, or check a public registry like chainlist.org. Confirming the chain ID is a quick way to make sure a wallet or application is signing for the network you intend.



