What changed, and why it matters
This is a small code cleanup in Electrum's Nostr Wallet Connect (NWC) plugin. The developer stopped modifying an incoming message object directly and instead passes the needed data as separate function parameters. The commit message says the goal is to make the underlying Event class immutable in the future. There is no direct security bug being fixed here, but the change removes a fragile pattern where error responses depended on whether the message had been previously altered.
No immediate action required. Treat as routine maintenance. Reviewers may want to confirm that all callers of send_error and run_request_task pass error_restype/request_method correctly, and that no other code still mutates aionostr Event objects before the planned immutability change.
Security signals we found
Removal of in-place mutation of an external library object (aionostr Event)
Defensive refactor to avoid relying on mutated object state for error response type
No mention of vulnerability, CVE, bug, exploit, or security fix in commit title/message
Evidence from the diff
The patch removes event.content = content in NWCServer’s request handler and threads request_method explicitly through run_request_task and send_error as error_restype. Previously, send_error inferred the response type by checking whether causing_event.content had been replaced with a dict and reading its method field. After the patch, the method string is passed directly. This is a defensive refactor: it decouples error-response construction from the mutable state of the aionostr Event object. The commit message frames it as preparation for making Event immutable. No vulnerability, exploit primitive, or incident is described in the commit or references.
Changed components
electrum/plugins/nwc/nwcserver.pyNWCServer request handling and error response pathsInspect captured patch +17 / −12
diff --git a/electrum/plugins/nwc/nwcserver.py b/electrum/plugins/nwc/nwcserver.py
index c2cd925..88e57d8 100644
--- a/electrum/plugins/nwc/nwcserver.py
+++ b/electrum/plugins/nwc/nwcserver.py
@@ -335,7 +335,6 @@ class NWCServer(Logger, EventListener):
content = json.loads(content)
if not isinstance(content, dict):
raise Exception("malformed content, not dict")
- event.content = content
params: dict = content['params']
if not isinstance(params, dict):
raise Exception("malformed params, not dict")
@@ -362,30 +361,36 @@ class NWCServer(Logger, EventListener):
elif method == "list_transactions":
task = self.handle_list_transactions(event, params)
else:
- self.logger.debug(f"Unsupported nwc method requested: {content.get('method')}")
- await self.send_error(event, "NOT_IMPLEMENTED", f"{method} not supported")
+ self.logger.debug(f"Unsupported nwc method requested: {method}")
+ await self.send_error(event, "NOT_IMPLEMENTED", f"{method} not supported", error_restype=method)
continue
if task:
- await self.taskgroup.spawn(self.run_request_task(task, event))
+ await self.taskgroup.spawn(self.run_request_task(task, request_event=event, request_method=method))
- async def run_request_task(self, task: Awaitable, request_event: nEvent) -> None:
+ async def run_request_task(self, task: Awaitable, *, request_event: nEvent, request_method: str = None) -> None:
"""Catches request handling exceptions and send an error response"""
try:
await task
except Exception as e:
self.logger.exception("Error handling nwc request")
- await self.send_error(request_event, "INTERNAL", f"Error handling request: {str(e)[:100]}")
+ await self.send_error(
+ request_event, "INTERNAL", f"Error handling request: {str(e)[:100]}",
+ error_restype=request_method,
+ )
- async def send_error(self, causing_event: nEvent, error_type: str, error_msg: str = "") -> None:
+ async def send_error(
+ self,
+ causing_event: nEvent,
+ error_type: str,
+ error_msg: str = "",
+ *,
+ error_restype: str = None,
+ ) -> None:
"""Sends an error as response to the passed nEvent, containing the error type and message"""
to_pubkey_hex = causing_event.pubkey
response_to_id = causing_event.id
- res_type = None
- if isinstance(causing_event.content, dict): # we have replaced the content with the decrypted content
- if 'method' in causing_event.content:
- res_type = causing_event.content['method']
- content = self.get_error_response(error_type, error_msg, res_type)
+ content = self.get_error_response(error_type, error_msg, error_restype)
await self.send_encrypted_response(to_pubkey_hex, json.dumps(content), response_to_id)
@staticmethod
Why this scored 18/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.