make sure load_ast_data returns a dict with str keys
What changed, and why it matters
This commit fixes a data-type consistency bug in Electrum's wallet database loader. When loading very old wallet files, the code could return numeric (integer) dictionary keys instead of string keys. Because the rest of the program expects string keys, this mismatch could later cause crashes or unexpected behavior when the wallet tries to read or update stored data. The fix forces all keys to become strings by converting the data through JSON.
Treat as a low-risk hardening fix. Users with very old Electrum wallets should upgrade. Reviewers should verify that the JSON round-trip does not drop unsupported but previously preserved Python object types in legacy wallets.
Security signals we found
Type confusion in parsed wallet data: integer vs string dict keys
Potential crash or logic error when downstream code indexes wallet data by string keys
Fix normalizes legacy data via JSON round-trip, a known pattern for key coercion
Evidence from the diff
In electrum/json_db.py, maybe_load_ast_data() parses legacy wallet data using Python’s ast.literal_eval. That format could historically contain integer keys. The function then merged those values into a dict without normalizing key types. The patch adds a json.loads(json.dumps(data)) round-trip at the return point, which recursively coerces all dict keys to strings (JSON object keys are always strings). Type hints were also updated to Dict[str, Any] to make the contract explicit. This is a defensive correctness fix rather than a clear-cut vulnerability patch.
Changed components
electrum/json_db.pyJsonDB.maybe_load_ast_data()Legacy wallet import/upgrade pathInspect captured patch +5 / −4
diff --git a/electrum/json_db.py b/electrum/json_db.py
index e7d78f9..dbf3c3d 100644
--- a/electrum/json_db.py
+++ b/electrum/json_db.py
@@ -25,7 +25,7 @@
import threading
import copy
import json
-from typing import TYPE_CHECKING, Optional, Sequence, List, Union, Any
+from typing import TYPE_CHECKING, Optional, Sequence, List, Union, Dict, Any
import jsonpatch
import jsonpointer
@@ -115,7 +115,7 @@ class JsonDB(Logger):
if self.storage and self.storage.file_exists():
self.write_and_force_consolidation()
- def load_data(self, s: str) -> dict:
+ def load_data(self, s: str) -> Dict[str, Any]:
if s == '':
return {}
try:
@@ -138,7 +138,7 @@ class JsonDB(Logger):
self.set_modified(True)
return data
- def maybe_load_ast_data(self, s):
+ def maybe_load_ast_data(self, s) ->Dict[str, Any]:
""" for old wallets """
try:
import ast
@@ -155,7 +155,8 @@ class JsonDB(Logger):
self.logger.info(f'Failed to convert label to json format: {key}')
continue
data[key] = value
- return data
+ # json roundtrip: recursively converts int keys to str
+ return json.loads(json.dumps(data))
def maybe_load_incomplete_data(self, s):
n = s.count('{') - s.count('}')
Why this scored 31/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.