onion_message: num_hops in blinded path is byte, not int.
What changed, and why it matters
This commit fixes a data-format bug in Electrum's Lightning onion-message handling. The number of hops in a 'blinded path' was being stored as a plain integer, but the protocol expects a single byte. The patch changes it to a bytes object. A second change only improves an error message when no reply path can be created. The fix is small and appears to prevent interoperability or parsing problems rather than a direct theft-of-funds vulnerability.
Treat as a normal bugfix patch. Review whether num_hops can ever exceed 255 and add an explicit bounds check if not already present. No urgent security response is indicated by the commit itself.
Security signals we found
Protocol serialization mismatch in a Lightning network message field
Field changed from Python int to single byte to match expected wire encoding
No explicit security claim, CVE, or advisory referenced in commit
No bounds check added; relies on existing len(onionmsg_hops) being <= 255
Evidence from the diff
In electrum/onion_message.py, create_blinded_path() now sets ‘num_hops’ to bytes([len(onionmsg_hops)]) instead of len(onionmsg_hops). This aligns the serialized field with the BOLT-style wire format where num_hops is a 1-byte value. The second hunk updates an exception string in OnionMessageManager to mention ‘No active peers?’ as a possible cause. The diff is a two-line change with no explicit security framing by the project.
Changed components
electrum/onion_message.pyLightning onion message blinded path constructionOnionMessageManager reply-path error reportingInspect captured patch +2 / −2
diff --git a/electrum/onion_message.py b/electrum/onion_message.py
index 755e9de..29eef92 100644
--- a/electrum/onion_message.py
+++ b/electrum/onion_message.py
@@ -115,7 +115,7 @@ def create_blinded_path(
blinded_path = {
'first_node_id': introduction_point,
'first_path_key': blinding,
- 'num_hops': len(onionmsg_hops),
+ 'num_hops': bytes([len(onionmsg_hops)]),
'path': onionmsg_hops
}
@@ -604,7 +604,7 @@ class OnionMessageManager(Logger):
path_id = self._path_id_from_payload_and_key(payload, key)
reply_paths = get_blinded_reply_paths(self.lnwallet, path_id, max_paths=1)
if not reply_paths:
- raise Exception(f'Could not create a reply_path for {key=}')
+ raise Exception(f'Could not create a reply_path for {key=}. No active peers?')
final_payload['reply_path'] = {'path': reply_paths}
Why this scored 22/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.