Skip to content

Reject unknown TLVs in blinded payment payloads#4546

Open
officialasishkumar wants to merge 3 commits intolightningdevkit:mainfrom
officialasishkumar:2026-04-blinded-tlv-reject
Open

Reject unknown TLVs in blinded payment payloads#4546
officialasishkumar wants to merge 3 commits intolightningdevkit:mainfrom
officialasishkumar:2026-04-blinded-tlv-reject

Conversation

@officialasishkumar
Copy link
Copy Markdown

Fixes #4442.

Blinded payment payload decoding still applied the normal odd/even TLV handling, which let unexpected outer custom TLVs and unknown encrypted blinded TLVs slip through on blinded paths. This tightens both layers so blinded payloads now reject non-allowlisted TLVs instead of silently ignoring them.

The test updates keep the behavioral coverage aligned with the new decoding rules: the blinded payment flow now expects the recipient to reject custom TLVs on a blinded path, and the max-path-length tests stay focused on sender-side sizing logic.

Testing:

  • cargo test -p lightning custom_tlvs_to_blinded_path
  • cargo test -p lightning unknown_odd
  • cargo test -p lightning one_hop_blinded_path_with_custom_tlv
  • cargo test -p lightning blinded_path_with_custom_tlv

Tighten blinded payload decoding so unexpected odd TLVs and custom TLVs are rejected instead of silently ignored. This applies both to the encrypted blinded TLV streams and to the outer blinded onion payload reader, matching BOLT 4's stricter allowlist behavior for blinded paths.

Update the blinded payment tests to expect recipient rejection of non-compliant custom TLVs and keep the max-path-length coverage focused on sender-side sizing logic. Add focused codec tests for the unknown-TLV decode paths.
@ldk-reviews-bot
Copy link
Copy Markdown

ldk-reviews-bot commented Apr 7, 2026

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@ldk-reviews-bot ldk-reviews-bot requested a review from wpaulino April 7, 2026 20:42
@ldk-claude-review-bot
Copy link
Copy Markdown
Collaborator

ldk-claude-review-bot commented Apr 7, 2026

I've completed a thorough re-review of all files and hunks in this PR. I verified:

  1. Inner encrypted TLV callbacks in BlindedPaymentTlvs::read and BlindedTrampolineTlvs::read - correctly handle padding (type 1), reject unknown odd types, and defer unknown even types to the macro's default rejection.

  2. Outer onion TLV tracking in InboundOnionPayload::read and InboundTrampolinePayload::read - has_unknown_odd_tlvs correctly flags unknown odd types < 65536, has_disallowed_blinded_tlvs correctly combines with custom TLVs check, and all blinded path variants (Forward, Dummy, Receive for payment; Forward, Receive for trampoline) are guarded.

  3. TrampolineEntrypoint early return (line 3841) correctly skips the blinded TLV check since it's not a blinded path hop.

  4. Non-blinded paths remain unaffected - unknown odd types still silently skipped, custom TLVs still collected.

  5. New macro _init_and_read_tlv_stream_with_custom_tlv_decode correctly mirrors the pattern of _init_and_read_tlv_stream and properly uses the non-exported decode_tlv_stream_with_custom_tlv_decode! without $crate::.

  6. Spec test vector - Bob's encrypted payload contains type 561 (odd, unknown). With blinding_point: None on the update_add_msg, the decode error correctly produces HTLCFailureMsg::Relay + InvalidOnionPayload.

  7. Test TLV ordering - all appended test TLVs maintain monotonic ordering (65541 > 65539/65537, 21 > 18).

  8. PaymentId uniqueness in max_payment_path_len_tests - necessary since payments are no longer claimed between sends.

No issues found.

Copy link
Copy Markdown
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

thanks!

if msg_type < 1 << 16 {
if msg_type % 2 == 1 {
has_unknown_odd_tlvs = true;
return Ok(true);
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.

nit you can drop this line (similar below), returning Ok(false) universally is fine.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done, dropped the return Ok(true) lines in both places and now returning Ok(false) universally.

_init_tlv_field_var!(features, (option, encoding: (BlindedHopFeatures, WithoutLength)));
_init_tlv_field_var!(payment_secret, option);
_init_tlv_field_var!(payment_context, option);
_init_tlv_field_var!(is_dummy, option);
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.

Please add a new macro for this rather than breaking it out.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added _init_and_read_tlv_stream_with_custom_tlv_decode macro in ser_macros.rs that combines _init_tlv_field_var + decode_tlv_stream_with_custom_tlv_decode, following the same pattern as _init_and_read_tlv_stream. Both BlindedPaymentTlvs and BlindedTrampolineTlvs now use it.

…de macro

Add a new _init_and_read_tlv_stream_with_custom_tlv_decode macro that
combines _init_tlv_field_var and decode_tlv_stream_with_custom_tlv_decode,
mirroring how _init_and_read_tlv_stream combines init with decode_tlv_stream.
This avoids manually breaking out field var initialization from the TLV
stream decoding in BlindedPaymentTlvs and BlindedTrampolineTlvs.

Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blinded path payloads don't reject unknown TLVs per BOLT4

4 participants