Writing Fuzz Targets for Wallets: Avoiding Known Issues

Posted by bruno

Mar 3, 2026/22:32 UTC

Fuzzing Bitcoin wallets presents unique challenges compared to fuzzing parsers or single functions, due to their stateful nature, persistence, cryptographic operations, and dependence on chain state. Optimizing fuzz testing for such applications is essential to avoid performance and determinism issues. One significant optimization involves reducing the keypool size to a minimum when fuzzing. The keypool in Bitcoin wallets, like Bitcoin Core, is a pre-generated set of keys for future address generation, which can become costly in fuzzing contexts due to unnecessary HD key derivations and database interactions. By setting the keypool size to 1, unnecessary pre-allocations are avoided without hindering correct wallet behavior, significantly improving fuzzing efficiency.

Descriptor and miniscript parsing also require careful handling during fuzzing. Unbounded fuzz input can lead to computationally intensive parsing and validation, overshadowing more relevant wallet behaviors. Constraining descriptor complexity by limiting wrapper depth, subfragment counts, and derivation ranges helps focus fuzzing efforts on meaningful wallet operations rather than parser performance. Using structured input generators or custom mutators to enforce these constraints from the start further enhances fuzzing effectiveness.

Mocking the fee estimator and avoiding wallet encryption/decryption during fuzzing are other critical strategies for maintaining performance. Fuzz targets should replace real fee estimation logic with fuzz-controlled values to explore all code paths efficiently. Since wallet encryption is computationally expensive, it's advisable to work with unencrypted wallets unless specifically testing encryption-related behaviors. This approach allows for higher iteration rates and more focused fuzzing campaigns.

Efficient fuzzing also entails minimizing disk I/O and nondeterminism introduced by database-backed operations. Bitcoin Core achieves this by using mockable database backends for wallet fuzzing. Creating a "wrapped wallet" fixture that initializes a minimalistic, deterministic wallet setup for each fuzz iteration can drastically reduce setup overhead. This setup includes forcing descriptor mode, initializing chain-related state, reducing keypool size, and importing a controlled set of descriptors. Such optimizations allow fuzz targets to concentrate computational resources on testing wallet operations rather than repeatedly handling wallet setup tasks.

Overall, effective fuzzing of Bitcoin wallets requires not just random input generation but strategic avoidance of performance and determinism pitfalls. Through optimizations like minimizing keypool size, constraining descriptor complexity, mocking fee estimators, bypassing encryption routines, using in-memory databases, and employing wrapped wallet fixtures, fuzzing efforts can be significantly more productive, focusing on uncovering meaningful vulnerabilities and behavior insights.

Link to Raw Post
Bitcoin Logo

TLDR

Join Our Newsletter

We’ll email you summaries of the latest discussions from high signal bitcoin sources, like bitcoin-dev, lightning-dev, and Delving Bitcoin.

Explore all Products

ChatBTC imageBitcoin searchBitcoin TranscriptsSaving SatoshiDecoding BitcoinWarnet
Built with 🧡 by the Bitcoin Dev Project
View our public visitor count

We'd love to hear your feedback on this project.

Give Feedback