What changed, and why it matters
This is a small follow-up patch to a security check inside Sparrow Wallet's database loader. The change tightens how the app scans a wallet file's internal database schema for dangerous commands that could let an attacker run code or link to outside data. The new version also strips out table names before checking, so attackers can't hide a dangerous command inside a cleverly named table. It appears to be a hardening fix rather than the original security fix.
Treat as a defense-in-depth hardening patch. Review the prior commit(s) referenced by 'follow up' to understand the original vulnerability and confirm this follow-up closes all evasion paths. Continue validating untrusted wallet files in an isolated process and consider moving from regex-based filtering to a strict allow-list parser.
Security signals we found
Hardening of DDL injection filter in wallet file loader
New identifier-stripping step to prevent regex evasion via quoted table names
Broadened blacklist pattern for H2-specific dangerous objects (TRIGGER, ALIAS, LINKED TABLE)
Follow-up commit suggests prior related security work
Evidence from the diff
DbPersistence.java’s schema DDL validation was updated. The INVALID_SCHEMA_DDL_PATTERN regex was broadened to catch CREATE TRIGGER/ALIAS with optional FORCE, and LINKED TABLE anywhere. A new WALLET_SCHEMA_IDENTIFIER_PATTERN strips quoted wallet_* identifiers and then non-alphanumeric/underscore characters before matching. This reduces the chance of evading the dangerous-statement filter by embedding keywords inside quoted identifiers or obfuscating with special characters. The commit is titled only ‘follow up’ and no advisory or CVE is referenced.
Changed components
src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.javaWallet file import / schema validation pathH2 database DDL parsingInspect captured patch +5 / −2
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.java b/src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.java
index 9c7d78d..6b362fc 100644
--- a/src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.java
+++ b/src/main/java/com/sparrowwallet/sparrow/io/db/DbPersistence.java
@@ -64,7 +64,8 @@ public class DbPersistence implements Persistence {
public static final String MIGRATION_RESOURCES_DIR = "com/sparrowwallet/sparrow/sql/";
private static final Pattern JDBC_URL_INJECTION_PATTERN = Pattern.compile(";\\w+=");
private static final String H2_META_TABLE_MAP = "table.0";
- private static final Pattern INVALID_SCHEMA_DDL_PATTERN = Pattern.compile("CREATE\\s+FORCE\\s+(?:LINKED\\s+TABLE|TRIGGER|ALIAS)", Pattern.CASE_INSENSITIVE);
+ private static final Pattern INVALID_SCHEMA_DDL_PATTERN = Pattern.compile("LINKED\\s+TABLE|CREATE\\s+(?:FORCE\\s+)?(?:TRIGGER|ALIAS)", Pattern.CASE_INSENSITIVE);
+ private static final Pattern WALLET_SCHEMA_IDENTIFIER_PATTERN = Pattern.compile("\"wallet_[^\"\\x00-\\x1f]*\"");
private static final Map<String, String> VALID_COLUMN_DEFAULTS = Map.of("UTXOMIXDATA.MIXESDONE", "0", "FLYWAY_SCHEMA_HISTORY.INSTALLED_ON", "CURRENT_TIMESTAMP");
private HikariDataSource dataSource;
@@ -459,7 +460,9 @@ public class DbPersistence implements Persistence {
return;
}
- if(INVALID_SCHEMA_DDL_PATTERN.matcher(new String(metaPayload, StandardCharsets.ISO_8859_1)).find()) {
+ String rawDdl = new String(metaPayload, StandardCharsets.ISO_8859_1);
+ String schemaDdl = WALLET_SCHEMA_IDENTIFIER_PATTERN.matcher(rawDdl).replaceAll(" ").replaceAll("[^A-Za-z0-9_]", " ");
+ if(INVALID_SCHEMA_DDL_PATTERN.matcher(schemaDdl).find()) {
throw new StorageException("This is not a valid wallet file.\n\nWallet file contains unexpected database objects.");
}
}
Why this scored 57/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.