# Fuzzing Fuzz targets over every parser that consumes **untrusted input**: server responses (block headers, Merkle proofs, peer lists), wallet files (plaintext document and encrypted container), and user-pasted text (mnemonics, SLIP-132 keys, addresses, amounts). Each target encodes the parser's **error contract**: the exception types documented as its failure mode are swallowed, anything else escaping is a finding. Targets: `header` `merkle` `slip132` `bip39` `address` `coinamount` `walletdoc` `encfile` `peers` (see `FuzzTargets.cs` for each contract). ## Three ways to run **1. Corpus replay — automatic.** The seed corpus (including regression inputs for every crash found so far) replays through all targets on every `dotnet test` run via `FuzzCorpusTests`, so fixed findings cannot come back. **2. Built-in random smoke — no tooling.** Not coverage-guided, but catches shallow contract violations in seconds: ```bash dotnet run -- bip39 --random 50000 # target, iterations [, seed] ``` **3. Coverage-guided campaign — afl++.** The real thing; run it before a release or after touching any parser: ```bash apt install afl++ dotnet tool install --global SharpFuzz.CommandLine ./fuzz.sh header # one target per campaign ./fuzz.sh peers -V 3600 # extra args go to afl-fuzz ``` `fuzz.sh` builds Release, instruments `PalladiumWallet.Core.dll` (and NBitcoin) with SharpFuzz, and launches afl-fuzz with the target's seed corpus. Findings land in `findings//crashes/`. ## Triage workflow ```bash dotnet run -- findings//crashes/ # replay: full stack trace ``` Fix the parser (typed exception or graceful rejection — see the hardening commits for `Bip39.TryParse`, `ElectrumApi.ParsePeers`, `EncryptedFile.Decrypt` as examples), then add the input to `SeedCorpus` in `Program.cs` as a `regression-*` seed and regenerate with `dotnet run -- --make-seeds Corpus`. ## Findings so far The first smoke run found two real bugs, both reachable from untrusted input: - `Bip39.TryParse` crashed with `NotSupportedException` on restore text resembling no wordlist (NBitcoin's `Wordlist.AutoDetect` throws for its internal "Unknown" language). - `ElectrumApi.ParsePeers` crashed with `InvalidOperationException` on a peer list containing a JSON string with invalid UTF-8 bytes (parses fine, fails at `GetString()` transcoding) — attacker-controlled server data. Plus two hardening changes made so the `encfile`/`peers` contracts could be strict at all: `EncryptedFile.Decrypt` maps every malformed-container failure to `InvalidDataException` and bounds the PBKDF2 iteration count (a tampered file could previously demand 2^31 iterations, hanging the wallet at open), and `ParsePeers` tolerates any JSON shape.