# EIP-155 is not enforced, allowing attackers/malicious operators to profit from replaying transactions

zkSync's DefaultAccount doesn't enforce EIP-155, so legacy txs with v=27/28 lack chainId binding, letting attackers replay pre-EIP-155 mainnet txs to steal funds.

- Payout: Contest reward
- Severity: medium
- Program: zkSync
- Credited: OffsideLabs
- Disclosed: 2024-02-29
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-10-zksync-findings/issues/882
- Library page: https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-05
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:signature-replay

**Target:** L2 DefaultAccount contract and bootloader transaction encoding
**Root cause:** DefaultAccount.validateTransaction and bootloader encoding skip chainId in signature when reserved[0]==0 (legacy tx with v=27/28), disabling EIP-155 replay protection.
**Steps:**
1. Identify a legacy tx on mainnet/other EVM chain with v=27 or 28 (pre-EIP-155, no chainId in signature).
2. Submit same tx to zkSync with tx_type=0 and reserved[0]=0; bootloader omits chainId from encoded signature.
3. DefaultAccount.validateTransaction accepts signature without chainId check, executing the tx on zkSync.
**How found:** Code review of TransactionHelper.sol and DefaultAccount.sol revealed conditional chainId encoding based on reserved[0]; traced Rust code showing reserved[0] set to 0 when legacy tx v=27/28.
**Exploitation:** Attacker replays a victim's early pre-EIP-155 transaction on zkSync; if victim has funds on zkSync, the replayed tx transfers them to the original recipient (attacker if they were recipient) or operator collects gas fees.
**Insight:** Check whether signature schemes conditionally include chainId based on transaction fields; legacy v values 27/28 often signal missing replay protection.
