[Lightning-dev] CVE-2020-26895: LND Low-S Tx-Relay Standardness

Conner Fromknecht conner at lightning.engineering
Tue Oct 20 21:52:27 UTC 2020

Hash: SHA256

Hi all,

Today we are writing to disclose the details of CVE-2020-26895 as a follow up to
the partial disclosure sent to lightning-dev [1].

## Abstract

Prior to v0.10.0-beta, a malicious peer could force an lnd node to accept a
high-S ECDSA signature when updating new off-chain states. Though the signatures
are valid according to consensus rules, the mempool policy would reject
transactions containing high-S values, potentially leading to loss of funds if
time-sensitive transactions cannot be relayed and confirmed. We have no evidence
of the bug being exploited in the wild.

It affects all classes of lnd nodes: routing, merchant, mobile, etc.

The vulnerability was reported privately to the lnd team by Antoine Riard.

## Background

The lightning-rfc specifies a fixed-width, 64-byte encoding used to transmit
ECDSA signatures in the Lightning protocol, which differs from the DER-encoding
used at the consensus layer. For regular, on-chain transactions, signature
serialization is handled by the btcec library's Signature.Serialize() method
[2]. This method always normalizes signatures to their low-S variant before
performing the DER-encoding to ensure that the btcec library can't _produce_
high-S signatures.

Early in lnd's history, however, serialization modeled off btcec was added to
produce DER-encoded signatures directly from the fixed-width representation,
bypassing the conversion into big.Int representation used internally by btcec.
In doing so, retaining the low-S normalization behavior was overlooked, and so
Sig.ToSignatureBytes() [3] would return high-S DER signatures whenever the
fixed-size signature was encoded with a high-S value.

During unilateral closure, this can be exploited by an attacker to cause a
second-level HTLC-success transaction from being accepted to the mempool. If the
victim is unable to patch before the HTLC's CLTV expires, the attacker can then
broadcast their HTLC-timeout transaction and recover the full value of the HTLC
minus fees. On the other hand, lnd’s cooperative close fully verifies the remote
party’s signatures using full policy-aware verification. As a result, the only
exploitation vector occurs during the force close scenario.

## Updates to Lighting RFC

As noted by Riard during the process, the lightning-rfc is lacking in terms of
specifying how nodes should validate signatures accepted off-chain. Notably, the
signatures should be checked for conformation to both consensus _and_ tx-relay
standardness rules, and rejected otherwise. Riard has confirmed that he is
planning to submit an update to the specification incorporating these

## Patch

This vulnerability was fixed in v0.10.0-beta by converting all witness
construction methods in lnd to accept signatures according to the
input.Signature interface introduced in PR 4172 [4], which requires the passed
object to have a Serialize() method. lnwire.Sig does not have a Serialize()
method, and so cannot satisfy the interface. As a result, the relevant call
sites were updated to pass in a btcec.Signature, forcing witness signature
serialization through btcec's Serialize() method which includes low-S

Note: A high-S signature can be converted to a low-S one manually w/o software
changes, or by a 3rd party, assuming one is aware of the reason for rejection.

Though the above recommendation to the spec by Riard also mitigates the issue,
this approach was chosen because it could retroactively patch affected nodes if
they are upgraded before the HTLC deadline expires, as well as its covertness.
After upgrading, any outstanding broadcasts would be reattempted, this time
normalizing any previously-persisted high-S signatures into their low-S variant.

Following the disclosure, lnd will also introduce the full tx-relay standardness
checks that are to be added to the lightning-rfc, as this offers a more general
and complete approach to ensuring lnd always adheres to standardness rules.

## Timeline

04/03/2020 - Initial report from Antoine Riard
04/10/2020 - PR 4172 merged into master
04/29/2020 - lnd v0.10.0-beta released
08/20/2020 - lnd v0.11.0-beta released
10/08/2020 - Partial Disclosure sent to lightning-dev and lnd mailing list [1]
10/20/2020 - Full Disclosure sent to lightning-dev and lnd mailing list

## References

[1] https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-October/002819.html
[2] https://github.com/btcsuite/btcd/blob/ba530c4abb35ea824a1d3c01d74969b5564c3b08/btcec/signature.go#L47
[3] https://github.com/lightningnetwork/lnd/blob/0f94b8dc624cf0e96ddc8fe1b8e3bf4b3fc4c074/lnwire/signature.go#L92
[4] https://github.com/lightningnetwork/lnd/pull/4172
[5] https://gist.github.com/ariard/fb432a9d2cd3ba24fdc18ccc8c5c6eb4

Huge thanks to Antoine Riard for the responsible disclosure and for helping to
make lnd more safu. More information can be found in Antoine’s disclosure [5].

Conner Fromknecht



More information about the Lightning-dev mailing list