What changed, and why it matters
This is a one-line bug fix in Electrum's Lightning Network payment handling. The code was comparing a whole status object to a resolution value, which would always be false. The fix compares just the resolution status correctly. This likely changes when a specific payment timeout error is returned versus a generic payment-details error. It appears to be a correctness fix for Lightning multi-part payment handling, with possible security implications around error handling but no clear exploit shown.
Review the surrounding MPP state machine to confirm no other similar object-vs-value comparisons exist. Verify that returning MPP_TIMEOUT in this path does not introduce any information-leakage or probing risk. Apply the patch as it is a clear correctness fix.
Security signals we found
Lightning Network payment failure path logic error
Incorrect comparison between object and enum value
Change affects error code returned to remote peer for failed HTLCs
Potential for incorrect payment failure attribution (MPP timeout vs incorrect payment details)
Evidence from the diff
In electrum/lnworker.py, update_or_create_mpp_with_received_htlc() checks whether an incoming HTLC belongs to a multi-part payment (MPP) set that is no longer in WAITING state. The original code compared the entire mpp_status object (a dataclass/tuple-like status) against RecvMPPResolution.EXPIRED using ==, which would always be False because the types differ. The fix changes this to compare mpp_status.resolution == RecvMPPResolution.EXPIRED. This means the MPP_TIMEOUT onion failure code is now actually emitted when appropriate, instead of always falling through to INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS. This is a logic/typing bug with potential consequences for Lightning protocol compliance and user-facing payment failure reasons.
Changed components
electrum/lnworker.pyLightning Network MPP (multi-part payment) receive handlingOnion routing failure response generationInspect captured patch +1 / −1
### electrum/lnworker.py
@@ -3028,7 +3028,7 @@ def update_or_create_mpp_with_received_htlc(
if mpp_status.resolution > RecvMPPResolution.WAITING:
# we are getting a htlc for a set that is not in WAITING state, it cannot be safely added
self.logger.info(f"htlc set cannot accept htlc, failing htlc: {channel_id=} {htlc.htlc_id=}")
- if mpp_status == RecvMPPResolution.EXPIRED:
+ if mpp_status.resolution == RecvMPPResolution.EXPIRED:
raise OnionRoutingFailure(code=OnionFailureCode.MPP_TIMEOUT, data=b'')
raise OnionRoutingFailure(
code=OnionFailureCode.INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS,Why this scored 36/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.