Skip to content

lnwire: enforce bolt 4 rules for onion message final-hop payloads#10948

Open
bitromortac wants to merge 4 commits into
lightningnetwork:masterfrom
bitromortac:2607-fix-onionmessage
Open

lnwire: enforce bolt 4 rules for onion message final-hop payloads#10948
bitromortac wants to merge 4 commits into
lightningnetwork:masterfrom
bitromortac:2607-fix-onionmessage

Conversation

@bitromortac

Copy link
Copy Markdown
Collaborator

While reviewing #10789 (h/t to @vctt94), three BOLT 4 compliance gaps in onion message decoding came up but were deferred as out of scope.

This PR forces that we only accept a single final hop payload type and that we correctly handle even/odd acceptance. We could in principle also refactor OnionMessagePayload to only carry a single final hop TLV, but that would need further consumer changes.

When decoding an onion message payload, the loop that forwards
unrecognized final hop TLVs to higher layers skipped any entry with a
zero-length value. DecodeWithParsedTypesP2P marks a recognized type with
a nil map entry but records the raw bytes for an unknown type, and an
unknown odd TLV with an empty value is valid. Keying the skip off a
length check therefore dropped such a TLV instead of passing it through.

Test the recognized-type skip against a nil entry so a valid unknown odd
zero-length TLV is preserved.
BOLT 4 requires the final node to ignore an onion message whose
onionmsg_tlv contains an unknown even type, since even types are
"must understand". The TLV stream decoder does not enforce this on its
own: its parsed-type map collects unknown types of either parity, so an
even type such as 70 would otherwise be accepted as a final hop payload.

Reject any unknown even type during decode, regardless of its range. The
check runs before the final hop range skip so unknown even types below
type 64 are rejected as well.
BOLT 4 requires the final node to ignore an onion message whose
onionmsg_tlv contains more than one payload field, where payload fields
are the tlv types reserved for the final hop (type 64 and above). Decode
previously accumulated every such field it found, so a payload bundling
invoice_request, invoice, and invoice_error together was accepted.

Reject the payload when more than one final hop field is present. Every
entry collected in FinalHopTLVs is in the final hop range, so its count
is the number of payload fields. The round-trip test for multiple fields
becomes a rejection test, and the property test now draws at most one
payload field.
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label Jul 2, 2026
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

🔴 PR Severity: CRITICAL

gh pr view | 3 files | 157 lines changed

🔴 Critical (1 file)
  • lnwire/onion_msg_payload.go (+44/-7) - modifies Lightning wire protocol onion message payload decoding, enforcing BOLT 4 rules for final-hop payload types and even/odd TLV acceptance
🟢 Low (2 files)
  • lnwire/onion_msg_payload_test.go (+80/-22) - test-only changes, excluded from severity-driving classification
  • docs/release-notes/release-notes-0.22.0.md (+4/-0) - release notes update

Analysis

This PR changes lnwire/onion_msg_payload.go, which falls under lnwire/* (Lightning wire protocol messages) — a CRITICAL package per the classification rules, since it governs correctness of on-wire onion message decoding/validation. The change enforces BOLT 4 compliance for final-hop payload types (rejecting multiple final-hop payload types, and correctly handling even/odd TLV type acceptance rules), which directly affects protocol-level message parsing behavior and could impact interoperability or introduce parsing regressions if incorrect.

No bump conditions apply: only 2 non-test/non-generated files changed (well under the 20-file threshold) and ~55 non-test lines changed (well under 500), and only a single critical package (lnwire) is touched. Severity remains CRITICAL based on the wire-protocol package alone, and this warrants expert review given the correctness-sensitive nature of onion message decoding.


To override, add a severity-override-{critical,high,medium,low} label.

@saubyk saubyk added this to lnd v0.22 Jul 2, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in lnd v0.22 Jul 2, 2026
@saubyk saubyk moved this from Backlog to In progress in lnd v0.22 Jul 2, 2026
@saubyk saubyk added this to the v0.22.0 milestone Jul 2, 2026
@saubyk saubyk requested review from erickcestari and ziggie1984 July 2, 2026 14:27

@vctt94 vctt94 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

This resolves the onion-message payload comments: unknown even TLVs now fail regardless of range, unknown odd zero-length final-hop TLVs are preserved via the nil check, and multiple final-hop payload fields are rejected after collecting both known final-hop namespaces and unknown odd final-hop TLVs.

great job!

@erickcestari erickcestari left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🧅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

severity-critical Requires expert review - security/consensus critical

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

4 participants