fuzz: Skip adding descriptor to wallet if it cannot be expanded
What changed, and why it matters
This is a small hardening change to a fuzz test (automated randomized testing) for Bitcoin Core's wallet descriptor handling. It adds a check that a parsed wallet descriptor can be 'expanded' (converted into actual output scripts) before the test proceeds to add it to a wallet. This prevents the fuzzer from creating wallet state with descriptors that parse but cannot actually be used, which could cause later test steps to hit unexpected failures or assertions. It is a test-only fix and does not change production wallet behavior.
No production action required. Treat as a test-quality improvement. If running the fuzz target, pull this change to reduce false-positive crashes and improve coverage validity.
Security signals we found
Fuzz-test-only hardening
Defensive validation of descriptor expandability before wallet state mutation
Prevents potential assertion/crash paths in fuzz harness from malformed descriptors
Evidence from the diff
The commit modifies src/wallet/test/fuzz/scriptpubkeyman.cpp. The CreateWalletDescriptorFromString helper previously parsed a fuzzer-provided descriptor string and immediately wrapped it in a WalletDescriptor. The patch calls Descriptor::Expand(0, keys, scripts_temp, out_keys, &temp_cache) on the parsed descriptor first, and returns nullopt if expansion fails. This ensures only expand-able descriptors are passed into the wallet’s ScriptPubKeyMan during fuzzing, avoiding downstream failures caused by descriptors that parse but have invalid/expansion-time issues.
Changed components
src/wallet/test/fuzz/scriptpubkeyman.cppWallet descriptor fuzz test harnessInspect captured patch +7 / −0
diff --git a/src/wallet/test/fuzz/scriptpubkeyman.cpp b/src/wallet/test/fuzz/scriptpubkeyman.cpp
index 341543ff..d251df29 100644
--- a/src/wallet/test/fuzz/scriptpubkeyman.cpp
+++ b/src/wallet/test/fuzz/scriptpubkeyman.cpp
@@ -70,6 +70,13 @@ static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWal
std::vector<std::unique_ptr<Descriptor>> parsed_descs = Parse(desc_str.value(), keys, error, false);
if (parsed_descs.empty()) return std::nullopt;
+ // Verify expand succeeds before making WalletDescriptor
+ // Expansion results are not needed
+ FlatSigningProvider out_keys;
+ std::vector<CScript> scripts_temp;
+ DescriptorCache temp_cache;
+ if (!parsed_descs.at(0)->Expand(0, keys, scripts_temp, out_keys, &temp_cache)) return std::nullopt;
+
WalletDescriptor w_desc{std::move(parsed_descs.at(0)), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/1};
return std::make_pair(w_desc, keys);
}
Why this scored 19/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.