Verifying A Transaction Signed By A Hardware Wallet Before Submitting To The Blockchain

No matter if we are using Eternal, Lace, Yoroi, or Nami, most of us are using hardware wallets like a Ledger or Trezor to sign transactions.
During the signing process we look carefully at the display on the hardware wallet to check that the receiving address and the amount we entered into the computer is what the computer submitted to the hardware wallet for signing. In other words we use the hardware wallet to be sure our computers aren’t lying to us.

So now the hardware wallet signs the transaction and asks us to press a button on the device to submit the signed transaction. But how do we know that the hardware wallet signed the transaction the way we asked it to before we submit it to the blockchain?

I understand that hardware wallets fall under the category of “trusted hardware” but sorry, I don’t trust hardware wallets.

We know that Ledger made it possible to export private keys using Shamir backup without telling the community.
And we know that their codebase was very recently hacked and that people lost funds.
We know that some of their code is closed source so we can’t know everything the device might do.
We know their customer database was hacked.

So I think it is reasonable to ask: Is there a way to get between the hardware wallet and the online wallet to intercept the signed transaction and then decode it to be sure that it says what we expect before submitting the transaction to the blockchain?

Much thanks for your responses.

1 Like

For example, in Eternl you can disable “Transaction: auto submit”, so that the transaction does not get automatically submitted when the Ledger is finished, anymore:
screenshot-2023-12-20-02:10:05

You can then inspect the transaction immediately before submitting it:
screenshot-2023-12-20-02:11:35

You can also download the signed transaction and inspect it with cardano-cli. In the downloaded file, I had to replace "Tx MaryEra" with "Witnessed Tx BabbageEra" to get it to work:

$ cardano-cli transaction view --tx-file eternl-tx-dffb81b7884113735a4f7c3c9dc8b5ab8d37c21a2f687ac54f43eac4e4d7c944-signed.txt
auxiliary scripts: null
certificates: null
collateral inputs: []
era: Babbage
fee: 177381 Lovelace
inputs:
- 257fdbe435fa1890f2dc65e6b0be668c0b5c06752909f30c4a85ae427b30b3f6#1
metadata: null
mint: null
outputs:
- address: addr1qyh72hvvrurjvddx4gq37jd2fzyef8scz9cwcyc90dffq0xxllh3nc5r82ujj36fy9zh0gryqvqy7r3ejd2h2kgsvryswhjr9q
  address era: Shelley
  amount:
    lovelace: 3000000
  datum: null
  network: Mainnet
  payment credential key hash: 2fe55d8c1f072635a6aa011f49aa4889949e181170ec13057b52903c
  reference script: null
  stake reference:
    stake credential key hash: c6ffef19e2833ab9294749214577a06403004f0e39935575591060c9
- address: addr1qyh72hvvrurjvddx4gq37jd2fzyef8scz9cwcyc90dffq0xxllh3nc5r82ujj36fy9zh0gryqvqy7r3ejd2h2kgsvryswhjr9q
  address era: Shelley
  amount:
    lovelace: 3000000
  datum: null
  network: Mainnet
  payment credential key hash: 2fe55d8c1f072635a6aa011f49aa4889949e181170ec13057b52903c
  reference script: null
  stake reference:
    stake credential key hash: c6ffef19e2833ab9294749214577a06403004f0e39935575591060c9
- address: addr1qyh72hvvrurjvddx4gq37jd2fzyef8scz9cwcyc90dffq0xxllh3nc5r82ujj36fy9zh0gryqvqy7r3ejd2h2kgsvryswhjr9q
  address era: Shelley
  amount:
    lovelace: 143938674
  datum: null
  network: Mainnet
  payment credential key hash: 2fe55d8c1f072635a6aa011f49aa4889949e181170ec13057b52903c
  reference script: null
  stake reference:
    stake credential key hash: c6ffef19e2833ab9294749214577a06403004f0e39935575591060c9
reference inputs: []
required signers (payment key hashes needed for scripts): null
return collateral: null
total collateral: null
update proposal: null
validity range:
  lower bound: 0
  upper bound: 111479091
withdrawals:
- address: stake1u8r0lmceu2pn4wffgayjz3th5pjqxqz0pcuex4t4tygxpjgygq2ay
  amount: 424185 Lovelace
  network: Mainnet
  stake credential key hash: c6ffef19e2833ab9294749214577a06403004f0e39935575591060c9
witnesses:
- key: VKey (VerKeyEd25519DSIGN "3fc45e94c669594e86e3e866b8be1171ec3168372ca25d6cdaaab0b83c0aba6d")
  signature: SignedDSIGN (SigEd25519DSIGN "ed374f98d1106d5c63e45642800d6e6aeea7b48461cb7dafd797506c68075e380abca0f4f9729eceaab9fb527d73db3777d4cb526a38d93153cae02f4e5f0f07")
- key: VKey (VerKeyEd25519DSIGN "69dd86c1a8b603d325d90e438832cdb1c0c8b83833c1e4bf4c09811934eb0f56")
  signature: SignedDSIGN (SigEd25519DSIGN "25555280f44f881725f5e57636e6771340156cea8d57505d9dbca009d8d825b49ba4856d36ceecfe60e7a62a191bae8626983aa6793e8862e4fb1c15b9e7a608")

Only gets you so far, of course. You’d have to trust that Eternl does not collude with Ledger in showing you something else than is actually sent to the blockchain in the end.

The FUD regarding Ledger is massively overblown in my personal opinion. Yes, they had some unnecessary fuck-ups. But neither getting their customer database hacked back in the days nor getting the CDN (not the code base itself) for some library used by dApps hacked recently was anywhere close to the code on the hardware device itself. The Recover option was communicated very, very badly, but not maliciously hidden and there is no indication whatsoever that they ever wanted to do anything nefarious without the user’s consent.

2 Likes

To add: I’ve never seen that possibility in one of the other wallet apps. Seems like one of those geeky things only Eternl offers.

Don’t know the details of the protocol right now, but I think only the signature, not the whole transaction comes back from the Ledger. So, it would have no possibility to actually change what is done in the transaction. That is determined by the wallet app actually building the transaction (or a dApp communicating with it).

Again, you’d have to trust the wallet app at least in that regard. (Using hardware wallet still makes sense since it still gives more security against malware and hacks on your computer even if you trust the wallet app itself.)

If you suspect the wallet app colluding with Ledger, you are basically toast.

By the way, I’m not sure at all about the “most of us” part. Yes, hardware wallets are advised everywhere by the OGs. But even they often seem to still do a lot of things with smaller “hot” wallets.

3 Likes

This is brilliant @HeptaSean! Much thanks!

If you suspect the wallet app colluding with Ledger, you are basically toast.

I just tried downloading the signed transaction as per your instructions.
So if I use cardano-cli transaction... as per your instructions then I don’t need to trust Eternl to tell me what it says. Is that correct?

The reason I think this is the case is because I suspect the signed transaction itself contains the public key which is used to decode the signed transaction. And the cardano-cli is telling us somewhere in the decoded transaction what public key it used to do the decoding. I can check that this is indeed my public key - the only key which can decode a message signed by my hardware wallet. So if the public key is mine and I agree that the decoded transaction reads correctly the I can safely submit the transaction using the cardano-cli

Am I thinking clearly on this?
Thanks for your help.

By the way, I agree with all your general statements on the context surrounding my question.

1 Like

If you then also submit that transaction yourself, you can be sure that what you have just seen is what is submitted to the chain (as long as you trust cardano-cli in that case).

If you just check with cardano-cli and then press submit on Eternl, they could – very theoretically – submit something else than they have shown you and exported to check with cardano-cli. (But if they are that rogue, they could have also just already submitted it ignoring your “no auto-submit” setting or could submit it even if you hit “cancel” or …)

But that all starts to get very academic. That would now be: Eternl creates a malicious transaction (whatever the malicious part may be), shows you something else, colludes with Ledger, so that the malicious part is also not shown when confirming on the hardware, and then also exports the fake non-malicious version to the file checked by cardano-cli. The collusion between Ledger and Eternl would also have to be that the Ledger signs both – the malicious transaction and the fake innocent one or cardano-cli would complain that something is off.

And that all would get noticed and called out very, very soon-ish if done on any relevant scale.


Checking what the transaction details say in the wallet app and trying to understand it is a very good habit, especially if the transaction comes from a dApp and not the wallet app itself, and very especially given the recent wave of scams.

Checking if what the Ledger says corresponds to what the wallet app says, is also a good idea. (No, I’m really not comparing every character of every address. Does anybody? But I hope I’d still catch if something is totally not what the wallet app told me.)

Downloading the transaction (signed, unsigned, or both) and comparing it with what Eternl says, is also valuable, but I think more from an educational point of view. Seeing different presentaions of what a transaction actually looks like, which details are there.

I would probably never do that on a regular basis as an extra security check.

2 Likes

That’s not necessary, only the first few (after the addr1q) and last few characters will suffice because you can’t immediately generate a key pair with such a hash, you’ll have to brute force guess this which will take some time.

Only if the real address/hash is known a long time beforehand, this can be achieved (the more characters that needs to be the same, the more time it’ll take, exponentially).

2 Likes