Transaction Malleability Attack

← Back to Chapter 3
1 A real malleated transaction from the Mt. Gox attack

On February 10, 2014 — three days after Mt. Gox suspended withdrawals — this transaction was confirmed in Block 285,160. It moved 1,882.71 BTC ($1.56M at the time). It is a confirmed malleated transaction — its scriptSig uses a non-standard encoding that changes the txid without invalidating the signature.

Confirmed Malleated Transaction Block 285,160
txid:3c6ebac0567ee0e116060f05ddf589730b4dcb79591d3c0837438acabbe47458
Date:February 10, 2014, 21:16 UTC
Input:1,882.71 BTC (single UTXO)
Outputs:4 outputs totaling 1,882.71 BTC
Fee:0.0005 BTC
2 How the scriptSig was malleated

The attacker used the most common malleation technique (28,595 of 29,139 documented attacks): replacing the single-byte push opcode with OP_PUSHDATA2, which uses a 3-byte encoding to push the same data. The signature and public key are identical — only the push opcode changes.

Normal ScriptSig (106 bytes)
47 3044...d401
21 02d36f...62f
47 = OP_PUSHBYTES_71 (push next 71 bytes)
21 = OP_PUSHBYTES_33 (push next 33 bytes)
Malleated ScriptSig (110 bytes)
4d 4700 3044...d401
4d 2100 02d36f...62f
4d 4700 = OP_PUSHDATA2 + length 0x0047 (71)
4d 2100 = OP_PUSHDATA2 + length 0x0021 (33)
Same data, different encoding = different txid
The signature bytes are identical. Only the push opcodes changed: 474d 4700 (1 byte → 3 bytes). This adds 4 bytes to the scriptSig, changing its hash — and therefore the txid — without touching the cryptographic signature.
3 Why this changes the txid

The txid is SHA-256d of the entire serialized transaction, including every byte of the scriptSig. Changing even one byte — even a push opcode that doesn't affect the signature — produces a completely different hash.

txid = SHA-256d( version + inputs + scriptSig + outputs + locktime )

Original scriptSig: 47 3044...d4 01 21 02d3...2f → txid X
Malleated scriptSig: 4d 4700 3044...d4 01 4d 2100 02d3...2f → txid Y

The original transaction (with txid X) was broadcast by the sender. The attacker intercepted it, replaced the push opcodes, and rebroadcast the malleated version (txid Y). The malleated version won the race to be mined in Block 285,160. The original txid X never existed on the blockchain.

4 How Mt. Gox was exploited

Mt. Gox tracked withdrawals by txid. When a customer requested a withdrawal, the exchange would broadcast a transaction and record its txid in the database. An attacker would:

  1. Request a withdrawal from Mt. Gox
  2. Watch the mempool for the withdrawal transaction
  3. Malleate the scriptSig (replace 47 with 4d 4700)
  4. Rebroadcast the malleated version
  5. If the malleated version confirms first, the original txid "disappears"
  6. Contact Mt. Gox support: "My withdrawal never arrived"
  7. Mt. Gox looks up the original txid — not found on-chain — and re-sends the BTC
What actually happened

The malleated transaction confirmed. The attacker received their BTC. The withdrawal was complete.

but
What Mt. Gox's system saw

The tracked txid doesn't exist on-chain. The system concludes the withdrawal failed and credits the account — enabling a second withdrawal of the same funds.

5 The scale: what BigQuery reveals

Using Google BigQuery's public Bitcoin dataset, we can find confirmed malleated transactions — those whose scriptSig starts with 4d (OP_PUSHDATA2) instead of a normal single-byte push opcode. During the Mt. Gox attack week (February 7–28, 2014), the largest confirmed malleated transactions include:

txid (truncated)BlockDateBTC
3c6ebac0...7458285,160Feb 101,882.71
403b6c19...045c285,161Feb 101,879.38
52a562a5...1e61285,149Feb 101,878.89
56ee4fdd...0617285,153Feb 101,874.83
733b66b1...63b4285,191Feb 111,867.79

According to Decker & Wattenhofer (ETH Zurich, 2014), 35,202 malleability conflict sets were detected between January 2013 and February 2014, involving 302,700 BTC. Of 28,595 attacks using the OP_PUSHDATA2 technique, 5,670 (19.46%) successfully confirmed the malleated version. The researchers concluded that while malleability attacks were real, they could not account for Mt. Gox's claimed loss of 850,000 BTC.

4 Bob's dependent transaction breaks

Bob, trusting the original txid, had already created transaction TX_B that spends his newly received coins. TX_B references TX_A's original txid as its input — but that txid doesn't exist anymore.

TX_B (Bob's spend) INVALID
Input:
References txid: a1b2c3d4...7890 ← DOES NOT EXIST
Output 0:0.99 BTC → merchant
Rejected by network: input references a txid that was never confirmed. Bob's payment to the merchant fails.

Bob's coins exist — they're in the output of TX_A' (txid f9e8d7c6...5432) — but TX_B points to the wrong txid. Bob must create a new transaction TX_B' that references the correct (malleated) txid.

5 The Mt. Gox exploit: how this becomes theft

Now imagine Bob is an exchange. Alice requests a withdrawal. The exchange sends TX_A, records txid a1b2c3d4...7890 in its database, and waits for confirmation. Alice (the attacker) malleates TX_A before it confirms.

What actually happened

TX_A' confirms. Alice receives her BTC. The withdrawal is complete.

but
What the exchange sees

The exchange searches for txid a1b2c3d4...7890 on the blockchain. It doesn't exist. The exchange concludes the withdrawal failed.

Alice contacts support: "My withdrawal never arrived." The exchange looks up the txid — not found. They re-send the BTC. Alice has now received double the intended amount. Repeat this thousands of times across automated systems, and you have the Mt. Gox exploit.

The Fix: Segregated Witness (Chapter 8)

SegWit moves the signature out of the data that gets hashed into the txid. The txid is computed from version + inputs + outputs + locktime — no scriptSig, no signature. Changing the signature changes the wtxid but not the txid. Dependent transactions can never be invalidated by signature malleation.

Pre-SegWit txid = hash( version + inputs + scriptSig + outputs + locktime )
SegWit txid = hash( version + inputs + outputs + locktime ) — signature excluded