fuzz: Reject too large descriptor leaf sizes in scriptpubkeyman target
What changed, and why it matters
This change adds a safety check to a Bitcoin Core fuzz test (an automated testing harness, not production wallet code). It rejects fuzz inputs that would create descriptor strings with unusually long 'leaf' segments before feeding them to the wallet's descriptor parser. The goal is to prevent the fuzzer from wasting time or hitting limits on pathologically large inputs, not to fix a user-facing security bug.
No urgent action. Treat as a routine fuzz-harness hardening commit. If reviewing, verify the 200-byte MAX_LEAF_SIZE is large enough to avoid excluding valid extended-key descriptors and that the structural-character list is complete for the descriptor grammar used in fuzzing.
Security signals we found
Adds an input-size guard in a fuzz target
Targets descriptor leaf length, which can affect parsing cost
No change to consensus, P2P, or production wallet parsing paths
Commit message frames the change as a fuzz-harness improvement
Evidence from the diff
The commit introduces HasTooLargeLeafSize() in src/test/fuzz/util/descriptor.{cpp,h} and calls it from the scriptpubkeyman fuzz target. It scans a descriptor-like byte buffer and resets a counter on structural characters ‘(‘, ‘)’, ‘,’, ‘{‘, ‘}’, counting everything else as a leaf. If any leaf exceeds 200 bytes, the fuzz input is discarded. This is a hardening of the fuzz harness’s input filtering, not a change to descriptor parsing logic used by normal wallet operations.
Changed components
src/test/fuzz/util/descriptor.cppsrc/test/fuzz/util/descriptor.hsrc/wallet/test/fuzz/scriptpubkeyman.cppInspect captured patch +29 / −0
diff --git a/src/test/fuzz/util/descriptor.cpp b/src/test/fuzz/util/descriptor.cpp
index 4e563eac..08ab7104 100644
--- a/src/test/fuzz/util/descriptor.cpp
+++ b/src/test/fuzz/util/descriptor.cpp
@@ -143,3 +143,23 @@ bool HasTooManyWrappers(std::span<const uint8_t> buff, const int max_wrappers)
return false;
}
+
+bool HasTooLargeLeafSize(std::span<const uint8_t> buff, const uint32_t max_leaf_size)
+{
+ uint32_t leaf_len{0};
+ for (auto c : buff) {
+ if (c == '(' || c == ')' || c == ',' || c == '{' || c == '}') {
+ // Possibly start a fresh leaf, or a fresh function name (with
+ // wrappers), or terminate a prior leaf.
+ leaf_len = 0;
+ } else {
+ // Just treat everything else as a leaf. This will also reject long
+ // function names, but this should be fine if the max_leaf_size is
+ // set large enough.
+ if (++leaf_len > max_leaf_size) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/src/test/fuzz/util/descriptor.h b/src/test/fuzz/util/descriptor.h
index 41605dd9..82cc967c 100644
--- a/src/test/fuzz/util/descriptor.h
+++ b/src/test/fuzz/util/descriptor.h
@@ -76,4 +76,12 @@ constexpr int MAX_WRAPPERS{100};
*/
bool HasTooManyWrappers(std::span<const uint8_t> buff, int max_wrappers = MAX_WRAPPERS);
+/// Default maximum leaf size. This should be large enough to cover an extended
+/// key, including paths "/", inside and outside of "[]".
+constexpr uint32_t MAX_LEAF_SIZE{200};
+
+/// Whether the expanded buffer (after calling GetDescriptor() in
+/// MockedDescriptorConverter) has a leaf size too large.
+bool HasTooLargeLeafSize(std::span<const uint8_t> buff, uint32_t max_leaf_size = MAX_LEAF_SIZE);
+
#endif // BITCOIN_TEST_FUZZ_UTIL_DESCRIPTOR_H
diff --git a/src/wallet/test/fuzz/scriptpubkeyman.cpp b/src/wallet/test/fuzz/scriptpubkeyman.cpp
index ff9d1cc0..deb1a579 100644
--- a/src/wallet/test/fuzz/scriptpubkeyman.cpp
+++ b/src/wallet/test/fuzz/scriptpubkeyman.cpp
@@ -66,6 +66,7 @@ static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWal
if (IsTooExpensive(MakeUCharSpan(mocked_descriptor))) return {};
const auto desc_str{MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)};
if (!desc_str.has_value()) return std::nullopt;
+ if (HasTooLargeLeafSize(MakeUCharSpan(*desc_str))) return {};
FlatSigningProvider keys;
std::string error;
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.