Bybit kept about 401,000 ETH in a cold wallet built on Safe, a widely used multi-signature contract, with each signer approving on a hardware wallet. On paper it was the setup this course has been building toward: cold, multi-signature, hardware-backed.
The attackers did not touch the wallets. They compromised a developer's machine at Safe and placed altered JavaScript in the storage that served Safe's web interface. The altered code activated only for Bybit's signer addresses. Everyone else who used Safe that week saw an honest interface.
On 21 February, Bybit moved funds from cold to warm storage, a routine operation. The interface showed each signer an ordinary transfer. The transaction actually delivered to their devices did something else: it changed the wallet's implementation contract, which handed control of the wallet to the attackers. The hardware wallet screens showed data the signers could not meaningfully read. They approved. When the last signature landed, the attackers drained the wallet.
About $1.46 billion left in minutes, the largest theft in the industry's history. Then the altered code put the original interface back, to cover its tracks.
Every hardware wallet did exactly what it was built to do. It signed what it was given. What it was given came from a screen the attackers controlled, and the device's own screen showed something the signers trusted less than the screen they could read.
The check that would have caught it, decoding the transaction's real content on a path the attackers did not control, was available. It was not done. The device is not the verification. The verification is a separate act.
The previous lesson left one question open: an air-gapped device sees only the transaction you carry to it, so what do you check before you let it sign? This lesson is that check, and Bybit is why it is the last lesson in the course rather than a footnote.
Three stages, two machines
Offline signing separates a transaction's life into three stages, and it matters which machine does each.
Build. The connected machine, the one with the wallet software and the network, assembles the unsigned transaction: what is being sent, to where, with what fee, calling what contract with what data. This machine is assumed compromised. That is the whole premise of having an offline signer.
Verify and sign. The unsigned transaction is carried to the offline device by QR code or card. The device shows what it can. You verify. The device signs. Only the signature comes back.
Broadcast. The connected machine attaches the signature and sends the transaction to the network. It cannot alter what was signed without invalidating the signature, so a compromised machine at this stage can delay or drop the transaction but cannot change it.
The stage that matters is the middle one, and the word doing the work is verify. The device does not verify. You do.
What the device can show
For a plain transfer, the device can show everything that determines the outcome: the destination address in full, the amount, the fee. A person can read those and compare them.
For a contract interaction, which is what a multi-signature transfer, a token approval and almost everything in F105's taxonomy actually is, the outcome is determined by a data field the device may not be able to decode. Some devices parse common contract calls and show a description. Many show a hash: a 64-character fingerprint of the data.
A hash is a promise that the data has not changed since it was hashed. It is a good promise. It is not a verification of what the data does, because the data was built by the machine you have assumed is compromised, and a compromised machine can build malicious data and hash it perfectly honestly.
The Bybit signers saw, on their devices, data they could not interpret. They had two screens: one they could read, controlled by the attackers, and one they could not, controlled by nobody. They trusted the readable one. That is the human default and it is the exact wrong choice, and the rest of this lesson is about giving yourself a third screen.
You are moving funds from your vault tier to your daily tier.
On the connected machine, build the transaction. Do not trust what it shows you; you are about to check it elsewhere.
Carry it to the offline device. The device displays the destination and amount.
Read the destination in full. Not the first four and last four characters. F105-04 covered why: address poisoning produces addresses that match at both ends by design.
Compare it against your own record, not against the sending interface. The daily tier's receiving address is in the specification you wrote in F104-06, on paper or in a file the connected machine did not produce. If the two match character for character, the destination is yours. If you are comparing against the interface that built the transaction, you have checked the attacker's work against the attacker's claim.
Read the amount. Then sign.
That is the whole procedure for a plain transfer. It is about ninety seconds, and it defeats interface substitution, address poisoning and clipboard replacement, which between them account for a large share of self-custody losses.
Verifying a contract call
When the device shows a hash or a data field, the procedure adds one step: decode the data on an independent path before signing.
Independent means not sharing the machine, the code, or the trust of the interface that built the transaction. In practice: take the unsigned transaction's raw data, which the device or the wallet software can export, and decode it with a separate tool, ideally on a separate machine, and read what it actually does. Which contract is called. Which function. With which arguments. If the interface said "transfer" and the decoding says "change implementation", you have found the Bybit transaction, and you stop.
Two things make this harder than it should be, and the course will not pretend otherwise. Decoding tools require some familiarity to read, which is why F105 exists. And the step is inconvenient exactly when you are in a hurry, which is why the next section exists.
If the other signers have already approved, it must be fine.
The other signers saw the same interface. In the Bybit theft, every signer approved, in sequence, each one looking at the same altered screen. The last signature was the one that mattered and it was given with the same confidence as the first.
Multi-signature protects against one signer being compromised or coerced. It does not protect against every signer being shown the same lie, because the signers are not independent paths; they are the same path, repeated.
A second signer is only a second verification if they verify on their own independent path. Written into the vault procedure, that means: each signer decodes the transaction themselves, and no one's approval is evidence for anyone else.
Write the procedure down
F104-06 had you write a specification with no secrets in it. This lesson adds a page to it: the signing procedure for the vault tier, written so that a second person could follow it, and so that the version of you in a hurry is bound by the version of you who was not.
The minimum:
- Where the reference addresses live, for every destination the vault is allowed to send to, on a medium the connected machine did not produce.
- The plain-transfer check: read the destination in full on the device, compare against the reference, read the amount, sign.
- The contract-call check: export the raw transaction, decode it on the independent tool named here, confirm the contract, the function and the arguments match the intent, sign.
- The stop rule: any mismatch between what the interface claims and what the device or the decoder shows ends the session. Not a small amount to test it. Ends it.
- For multi-signature: each signer performs the checks independently and no signer's approval counts as verification for another.
A procedure that is only followed when convenient protects nothing. Bybit's signers were experienced, well-equipped and in a hurry on a routine day, which is the day the procedure is for.
Closing F104
You arrived at this course with the taxonomy and the tiers. You leave it with a specification: what each tier is made of, where its seed's randomness came from, whether it is air-gapped and why, and the written procedure for signing from it. That page has no secrets on it and it is the technical half of what F110 will ask you to leave behind.
F104-L1 builds the tiers in the sandbox on BSC testnet, funded from the faucet, so every mistake in the building costs nothing. F104-L2 is the wipe drill, and it is the component of the Custody Practical that this whole course has been preparing you to pass. Do them for real: a setup that has never held anything, even test funds, has never been tested. Repeating the build with small real funds on your own devices is worth doing and is yours to do; the platform never asks for it.
Offline signing is three stages on two machines: build on the connected machine, verify and sign on the offline device, broadcast from the connected machine. The device signs what it is given and shows what it can parse, and a hash on its screen is a promise about the data's integrity, not a verification of its intent. Verify a plain transfer by reading the full destination on the device and comparing it against your own record, never against the interface that built it. Verify a contract call by decoding the raw data on an independent path, because the Bybit signers approved a screen they could read over a screen they could not, and the readable one was the attacker's. Write the procedure down, with a stop rule, and follow it on the routine day, which is the day it is for.
