Skip to content

sending with Lightning: payment_preimage validation is skipped on Android

High
SomberNight published GHSA-9gpc-prj9-89x7 Sep 12, 2023

Package

electrum

Affected versions

4.0.0<=x<4.4.0 (Android)

Patched versions

4.4.0

Description

Impact

When using Lightning in Android builds of Electrum, when sending payments, the direct channel counterparty could steal the payment amount being sent without actually forwarding it. This is because when receiving an update_fulfill_htlc message the preimage actually hashing to the payment_hash was only checked in an assert, and asserts were disabled in Android builds.

In Lightning, payments are made using HTLCs. Consider an Alice->Bob->Carol->Dave multi-hop payment, where the Electrum client is Alice. After Alice sends an HTLC for hash(R) to Bob, Bob is expected to forward it to Carol (who would then forward it to Dave) and wait for it to be either fulfilled or failed. Only the final recipient, Dave, knows the preimage R for hash(R), which is required to fulfill the HTLC. Bob can decide not to forward to Carol and simply fail the HTLC back to Alice directly. However, Bob cannot normally decide to fulfill the HTLC directly without forwarding as that requires knowing the preimage R. When Bob receives the preimage from Carol (as part of Carol fulfilling the HTLC Bob sent to her), Bob can then fulfill Alice's HTLC and take the money from Alice. Bob knowing the preimage and showing it to Alice is proof that Bob indirectly paid Dave, and so Alice pays Bob.

The bug is that Bob can claim to have paid Carol/Dave, show a fake/invalid preimage to Alice, and take Alice's money (the payment amount) without actually forwarding the money. This is because Alice does not validate that the preimage presented by Bob is actually correct (as the check is an assert[6] and asserts were disabled in Android builds).

Except for Android, other users running the official binaries are not affected.

Users running from source are expected not to be affected. It is possible to disable asserts, by passing the -O command-line flag to the python interpreter[1]. As far as we could tell no mainstream Linux distribution does this - it would have to be explicitly passed by the user. That is, when running from source, asserts should normally be enabled and hence users not affected.

We have no knowledge of in-the-wild exploitation of the vulnerability.

Patches

We enabled asserts in the Android binaries, released in version 4.4.0 [0].
A check was added that asserts are enabled in all cases, even when running from source, released in version 4.4.5 [2][3].

How to know if I was affected?

As the attack involved the recipient not getting paid, the recipient would presumably tell the victim that they have not received any money. For example, if paying a merchant with an online interface, the merchant would not mark the invoice as paid.

References

[0]: https://github.com/spesmilo/electrum/commit/0e5464ca13ce2f993107b4a293982ea4bfc434b5
[1]: https://docs.python.org/3/using/cmdline.html#cmdoption-O
[2]: https://github.com/spesmilo/electrum/commit/ccc012674fc5707145aadf035440f6d63c9d5bbc
[3]: https://github.com/spesmilo/electrum/commit/d1c881080fd21733bc21bd6b61e62247a2960a9d
[4]: https://github.com/spesmilo/electrum/commit/0f541be6f11a372d202c99476e6d051184006bba
[5]: https://github.com/spesmilo/electrum/commit/e23c6c70501a1d4bc7bba34438ce7b4e84894191
[6]: https://github.com/spesmilo/electrum/blob/1ca05f32435a23e561841e1b620b1c7620c29d83/electrum/lnchannel.py#L1432

Timeline

  • 2023-03-31: A newly introduced security check was using an assert. This was caught during code review and replaced with a standard exception. As part of the review and discussion, we realised that asserts had been disabled in the Android builds, and enabled them[0] as a precautionary measure. A check was added that enforced that asserts are enabled when Electrum is running as part of a binary build (on any platform). When running from source, we still tolerated asserts being disabled and simply logged a warning[4].
  • 2023-04-18: version 4.4.0 released, including the above changes.
  • 2023-06-01: We noticed HTLC preimages were only tested using an assert, and realised the implications. Due to the exploitable nature of this issue, the assert was left as-is. We assessed that the prior change[0] meant that users running >=4.4.0 are safe. Still, the previously added check that enforced asserts were enabled in binary builds was replaced with a broader check that hard-failed if asserts were disabled, on any platform even when running from source[2], backported to the 4.4.x branch and released in 4.4.5. As Android users of old versions (<4.4) were vulnerable, based on Google Play version distribution statistics, we decided to delay public disclosure.
  • 2023-06-20: version 4.4.5 released.
  • 2023-08-22: We added a notice in the release notes[5] about upcoming disclosure.
  • 2023-09-12: Public disclosure of the issue.

Severity

High

CVE ID

No known CVE

Weaknesses

No CWEs