What was found
On 12 November 2026, Trezor published the results of its investigation into devices sold by CryptoBilis, a reseller in Southeast Asia. Three Trezor Safe 5 units contain a hidden implant. One was examined in Trezor's lab; two were identified from photos of the internals sent by their owners. All three were bought between 20 August and 23 September 2026.
The implant is an extra board between the main board and the display, with a cellular module and an antenna. Trezor says it only listens: it reads what the screen shows, which during setup includes the recovery phrase, encrypts it and sends it over the mobile network to a server run by the attackers. Ledger described the same technique in its own devices from resellers in the region on 15 October, and said its chip, OS and servers were not compromised.
On 11 November Trezor shipped firmware 2.13.1, which it says stops the implants it has found from capturing anything. Owners who already set up an affected device still need a new wallet with a new seed, because a captured seed stays captured.
The part you can't check
Trezor is blunt about home inspection: weighing isn't a reliable test, and there's no dependable way to inspect a device yourself. The real defence against a tampered unit is provenance. Buy from the manufacturer or a reseller it lists, and treat anything else as untrusted before it ever shows you a seed.
The part you can check
Everything else you install around the wallet is software: the companion app, firmware files if you update offline, CLI tools. Vendors publish hashes or signatures for those, and comparing a SHA-256 takes a few lines. This is the same habit, applied to the layer where a check is possible.
The script below streams a file through SHA-256 and compares it to a published value with a constant-time comparison. Node 18+, no dependencies.
// verify-sha256.mjs: hash a file with SHA-256 and compare it to a published value. // Usage: node verify-sha256.mjs <file> <expected-hex> // Exit 0 = match, 1 = mismatch, 2 = usage error. Node 18+, no dependencies. import { createHash, timingSafeEqual } from 'node:crypto'; import { createReadStream } from 'node:fs'; const [file, expectedRaw] = process.argv.slice(2); if (!file || !expectedRaw) { console.error('usage: node verify-sha256.mjs <file> <expected-hex>'); process.exit(2); } const expected = expectedRaw.trim().toLowerCase().replace(/^sha256:/, ''); if (!/^[0-9a-f]{64}$/.test(expected)) { console.error('expected value must be 64 hex characters'); process.exit(2); } const hash = createHash('sha256'); for await (const chunk of createReadStream(file)) hash.update(chunk); const actual = hash.digest('hex'); const same = timingSafeEqual(Buffer.from(actual, 'hex'), Buffer.from(expected, 'hex')); console.log(`file: ${file}`); console.log(`actual: ${actual}`); console.log(`expected: ${expected}`); console.log(same ? 'MATCH' : 'MISMATCH: do not install this file'); process.exit(same ? 0 : 1); A test run against a small sample file, once with the right hash and once with the first character changed:
$ node verify-sha256.mjs sample.bin 52b8b6e0b62055ca1dff4b6afaae30faf606861ba15efee2367ba84ad92baebb file: sample.bin actual: 52b8b6e0b62055ca1dff4b6afaae30faf606861ba15efee2367ba84ad92baebb expected: 52b8b6e0b62055ca1dff4b6afaae30faf606861ba15efee2367ba84ad92baebb MATCH exit 0 $ node verify-sha256.mjs sample.bin 02b8b6e0b62055ca1dff4b6afaae30faf606861ba15efee2367ba84ad92baebb ... MISMATCH: do not install this file exit 1 A few notes on the choices:
- Streaming keeps memory flat, so a large installer works the same as a small file.
-
timingSafeEqualmatters little for a local check, but it costs nothing and keeps the habit right if the code ends up in a service. - The exit code lets you drop it into a shell script or CI step:
node verify-sha256.mjs app.dmg "$HASH" && open app.dmg. - Get the expected value from the vendor's own site over HTTPS, not from the same mirror that served the file. A hash from the same place as the file only proves the download wasn't corrupted.
Where a hash stops helping
A matching hash proves the file is the one the publisher listed. It says nothing about the device you run it on, and it can't detect a board soldered between a display and a mainboard. For that the only answers are where you bought the device, and a fresh seed if you're not sure.
If you bought a Trezor from CryptoBilis from March 2026 onwards, Trezor's advice is to move funds to a new wallet with a new seed, not to set up an unused device, and to contact its support. Nobody legitimate will ask for your recovery phrase.
Sources: Trezor, "Our CryptoBilis investigation: what we found and what we've changed" (12 Nov 2026); Trezor, "Implant reported in a Trezor sold by CryptoBilis" (30 Oct 2026); Ledger, "Ledger's Response to the Hardware Implant Attack" (15 Oct 2026).

