fix regression from jdk25 update causing silent skips when importing jsonl wallet label lines
What changed, and why it matters
This commit fixes a bug where importing wallet labels from a JSONL file could silently skip some lines after a Java runtime update. The fix adds a required empty constructor for a label class and corrects how key derivation data is copied so it can be safely reused after the original source data is no longer available.
Users importing wallet labels from JSONL should upgrade to a build containing this commit. Review whether any labels imported under the affected JDK 25 build were silently skipped and re-import if needed. No immediate exploit mitigation is required.
Security signals we found
Silent data loss / import skip on deserialization failure
Mutable object reference reuse in key derivation copying
Regression tied to JDK/Gson runtime compatibility
Evidence from the diff
The patch addresses two regressions introduced by a JDK 25 update in WalletLabels.java. First, it adds a no-argument constructor to the private static Label class, which Gson deserialization requires; without it, some JSONL wallet label import lines may be silently skipped. Second, it changes Origin.fromOutputDescriptor() to create new KeyDerivation objects rather than reusing references from the output descriptor’s map values. The original values may be mutable or tied to the descriptor’s lifecycle, so copying them avoids potential data corruption or loss when the descriptor is later modified or garbage collected.
Changed components
src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.javaWallet label JSONL importOrigin.fromOutputDescriptor()Inspect captured patch +7 / −1
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java b/src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java
index 7cc818c..f22fa85 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/WalletLabels.java
@@ -451,6 +451,10 @@ public class WalletLabels implements WalletImport, WalletExport {
}
private static class Label {
+ public Label() {
+ //required for Gson deserialization
+ }
+
public Label(Type type, String ref, String label, String origin, Boolean spendable) {
this.type = type;
this.ref = ref;
@@ -562,7 +566,9 @@ public class WalletLabels implements WalletImport, WalletExport {
public static Origin fromOutputDescriptor(OutputDescriptor outputDescriptor) {
Origin origin = new Origin();
origin.scriptType = outputDescriptor.getScriptType();
- origin.keyDerivations = new HashSet<>(outputDescriptor.getExtendedPublicKeysMap().values());
+ origin.keyDerivations = outputDescriptor.getExtendedPublicKeysMap().values().stream()
+ .map(keyDerivation -> new KeyDerivation(keyDerivation.getMasterFingerprint(), KeyDerivation.writePath(keyDerivation.getDerivation())))
+ .collect(Collectors.toCollection(HashSet::new));
return origin;
}
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.