Skip to content

Reject unknown TLVs in blinded payment payloads#4546

Open
officialasishkumar wants to merge 1 commit intolightningdevkit:mainfrom
officialasishkumar:2026-04-blinded-tlv-reject
Open

Reject unknown TLVs in blinded payment payloads#4546
officialasishkumar wants to merge 1 commit 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

@ldk-reviews-bot
Copy link
Copy Markdown

ldk-reviews-bot commented Apr 7, 2026

👋 I see @wpaulino was un-assigned.
If you'd like another reviewer assignment, please click here.

@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

Good - non-blinded paths (lines 3950-3981) don't check has_disallowed_blinded_tlvs, so custom TLVs and unknown odd types continue to work as before for regular payments.

No issues found.

The PR correctly implements rejection of unknown TLVs in blinded payment payloads at two layers:

  1. Inner encrypted TLVs (BlindedPaymentTlvs::read, BlindedTrampolineTlvs::read): New custom TLV callback rejects unknown odd types while allowing padding (type 1), and defers unknown even types to the macro's default rejection.
  2. Outer onion TLVs (InboundOnionPayload::read, InboundTrampolinePayload::read): Tracks unknown odd types < 65536 and custom TLVs >= 65536 via has_disallowed_blinded_tlvs, rejecting them for all blinded path variants (Forward, Dummy, Receive, and trampoline Forward/Receive).

Non-blinded paths remain unaffected. The TrampolineEntrypoint correctly skips the blinded TLV check. Test coverage is adequate across unit tests and integration tests. The spec test vector update correctly stops at Bob's rejection of the unknown type 561 in the encrypted payload. The new _init_and_read_tlv_stream_with_custom_tlv_decode macro properly mirrors _init_and_read_tlv_stream while accepting the custom decoder callback.

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.

@ldk-reviews-bot
Copy link
Copy Markdown

🔔 1st Reminder

Hey @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMatt
Copy link
Copy Markdown
Collaborator

Cool, thanks. Please rebase so the new macro is in the first commit and the last commit isn't rewriting stuff in the first commit. Also please change your commit message to not be longer than 70 chars long - word wrap also the commit message body.

@TheBlueMatt TheBlueMatt removed the request for review from wpaulino April 9, 2026 22:17
Reject unknown odd TLVs and disallowed custom TLVs when decoding
blinded payment and trampoline payloads.

Add a dedicated helper macro for TLV readers with custom decode
callbacks and update the affected tests to cover the stricter
validation paths.

Signed-off-by: Asish Kumar <[email protected]>
@officialasishkumar officialasishkumar force-pushed the 2026-04-blinded-tlv-reject branch from a57f64d to 6da7ec7 Compare April 10, 2026 14:11
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