What changed, and why it matters
This commit fixes a bug in Electrum's Lightning payment handling. When a background callback task finished, the code tried to read a payment record that might already have been deleted, causing a KeyError. The fix removes that unsafe lookup and instead sends any callback failure to the crash reporter. It is a robustness fix rather than a security vulnerability; the error was noisy and could hide real callback failures, but there is no evidence it could be exploited to steal funds or bypass protections.
Treat as a routine bug-fix / reliability improvement. Reviewers may want to verify that send_exception_to_crash_reporter does not leak sensitive callback context, but no urgent security response is indicated.
Security signals we found
Exception handler itself raised KeyError, potentially masking original callback failures
Crash reporter now receives callback exceptions instead of them being swallowed by a bad log statement
No input validation or authorization boundary changed
No cryptographic or Lightning protocol invariant changed
Evidence from the diff
In lnpeer.py, _run_htlc_switch_iteration schedules an asyncio callback task and adds a done_callback to log exceptions. The old lambda captured payment_key and indexed self.lnworker.received_mpp_htlcs[pk], but by the time the done_callback runs the payment key may have been removed from received_mpp_htlcs, raising KeyError. The new code simply forwards any exception to util.send_exception_to_crash_reporter and avoids the dictionary lookup. This prevents a secondary exception in the exception handler and ensures callback failures are reported.
Changed components
electrum/lnpeer.pyLightning HTLC switch iteration callback handlingCrash reporter integrationInspect captured patch +2 / −4
diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
index e241e3f..39a17db 100644
--- a/electrum/lnpeer.py
+++ b/electrum/lnpeer.py
@@ -2901,10 +2901,8 @@ class Peer(Logger, EventListener):
self._fulfill_htlc_set(payment_key, preimage)
if callback:
task = asyncio.create_task(callback())
- task.add_done_callback( # log exceptions occurring in callback
- lambda t, pk=payment_key: self.logger.exception(
- f"cb failed: "
- f"{self.lnworker.received_mpp_htlcs[pk]=}", exc_info=t.exception()) if t.exception() else None
+ task.add_done_callback( # handle exceptions occurring in callback
+ lambda t: (util.send_exception_to_crash_reporter(t.exception()) if t.exception() else None)
)
if len(self.lnworker.received_mpp_htlcs[payment_key].htlcs) == 0:
Why this scored 25/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.