Zebra Coverage-Guided Fuzzing Infrastructure

Hello everyone,

I am submitting a proposal to Zcash Community Grants (ZCG) to build a coverage-guided fuzzing infrastructure for Zebra, the Zcash Foundation’s Rust consensus node implementation.

This project focuses on systematically testing Zebra’s critical parsing, networking, and cryptographic components against malformed inputs, enabling continuous, automated discovery of security vulnerabilities and edge-case bugs.


Why This Matters

Zebra currently has zero fuzzing coverage. There are no fuzz targets, no cargo-fuzz configuration, and no OSS-Fuzz registration. After NU7, Zebra becomes the sole consensus node for the entire Zcash network. Any exploitable parsing or validation bug could compromise the network’s security and user funds.

For comparison, Bitcoin Core maintains a mature fuzzing infrastructure with over 100 fuzz targets and continuous OSS-Fuzz integration. Zcash, as a privacy-focused cryptocurrency, arguably requires even more rigorous testing, yet has none.


Project Overview

This proposal introduces a complete fuzzing infrastructure for Zebra that includes:

  • Fuzz targets for all major attack surfaces: transaction and block deserialization, P2P protocol parsing, RPC input handling, script and address parsing, note commitment tree operations, and Equihash verification

  • Seed corpora extracted from Zcash mainnet real data

  • CI integration with PR-level smoke fuzzing and nightly extended fuzzing campaigns via GitHub Actions

  • OSS-Fuzz submission, enrolling Zebra in Google’s continuous fuzzing service for 24/7 automated testing

  • Security reporting with structured crash triage, severity classification, reproduction steps, and fix recommendations


Technical Approach

The infrastructure is built on cargo-fuzz with the libFuzzer backend. For complex inputs, the arbitrary crate enables structured fuzzing. All targets run with AddressSanitizer and UndefinedBehaviorSanitizer for maximum bug detection.

Fuzz targets are prioritized by attack surface:

  • P0 (Critical): Transaction deserialization (v1 through v5+), block and header parsing, P2P message parsing

  • P1 (High): RPC input handling, script and address parsing, note commitment tree operations

  • P2 (Medium): Equihash verification, Orchard and Sapling serialization


Deliverables and Milestones

The proposal is structured into three milestones over 6 months:

  1. Core Fuzzing Framework and Initial Targets — zebra-fuzz crate, 3+ fuzz targets for critical deserialization code, seed corpora from mainnet

  2. Extended Targets, Corpus Optimization and CI — 7+ total fuzz targets, corpus minimization, GitHub Actions CI integration, coverage reporting

  3. Security Analysis, OSS-Fuzz and Documentation — crash analysis report, OSS-Fuzz submission PR, documentation for community contributors, upstream PRs to Zebra


Budget

  • Startup Funding: $3,000 (infrastructure setup)

  • Milestones 1 through 3: $27,000 (engineering work)

  • Total: $30,000


Design Principles

  • Standalone: independent crate, no modifications to Zebra core code required

  • Sustainable: OSS-Fuzz integration ensures fuzzing continues indefinitely after project completion

  • Community-oriented: documentation enables anyone to add new fuzz targets as Zebra evolves


Full proposal details are available here:

Thank you for your time and feedback.

6 Likes

I’m supportive of this grant.

6 Likes

Hi all,

I reviewed this proposal and am supportive, with a few concerns I’d like the committee and proposer to address.

What I Like

Right tool, right scope. The technical approach is sound. cargo-fuzz with libFuzzer is the standard Rust fuzzing toolchain, and the phased milestone structure and $30K budget are reasonable for the scope of work.

OSS-Fuzz submission is the highest-value deliverable. If accepted, Google provides 24/7 continuous fuzzing at zero ongoing cost to the ecosystem. This is where the long-term ROI lives.

Concerns

Proposer credibility gap on fuzzing specifically. The proposer’s GitHub shows meaningful Rust experience, but I found no public evidence of fuzzing work. No fuzz targets, no crash triage, no OSS-Fuzz contributions. I also could not locate a GitHub profile for the co-proposer (aic-larry), who is listed as the primary implementer. The proposer appears to be using Claude Code (based on CLAUDE.md in their pinned repo), which is fine for development but makes it harder to evaluate their independent depth on security analysis and crash triage.

OSS-Fuzz acceptance is not guaranteed, and that changes the value equation. Google’s bar for inclusion is high. Projects must have a significant user base or be critical to global IT infrastructure. If Zebra is not accepted, the fuzzing infrastructure still has value, but becomes a material ongoing cost center (CI compute, corpus maintenance, someone to monitor and triage results). I’d recommend ZCG structure payment so that a meaningful portion of milestone 3 funding is gated on OSS-Fuzz submission acceptance, giving the proposers strong incentive to build a compelling case for inclusion.

Crash triage and severity assessment need more detail. Fuzzing safe Rust code will likely surface many panics and edge cases that are not security-critical. These are still worth fixing, but someone needs to distinguish “consensus node crashes on malformed input from an adversarial peer” from “unreachable panic in a rarely-exercised code path.” It’s not clear to me that the team has experience making these determinations in a consensus-node context. I’d like to see the proposer describe their triage framework and, ideally, point to prior experience assessing bug severity.

Recommendations

  1. Request a proof-of-concept: A single working fuzz target against Zebra’s transaction deserialization, before full grant approval. This would materially de-risk the grant.

  2. Require a GitHub profile or portfolio for aic-larry so the committee can vet the primary implementer.

  3. Gate a portion of milestone 3 on OSS-Fuzz acceptance to align incentives with the proposal’s highest-value deliverable. The proposer obviously can’t control Google’s decision here, but the committee can align incentives such that the proposer makes a compelling case for inclusion in the OSS-Fuzz program.

6 Likes

Hi alchemydc, thank you for the thoughtful feedback and support. I want to address your concerns — and share an important update.

Update first: Since posting our proposal, we’ve continued our PoC work and our deep fuzzing methodology has already uncovered a security issue that we’ve reported to the Zcash Foundation through Zebra’s official responsible disclosure process (GitHub Security Advisory, per Zebra’s SECURITY.md). We can’t share details until the disclosure process completes, but we believe this early finding validates both our approach and our team’s ability to deliver real security value.

Now to your specific points:

1. Team experience and aic-larry

aic-larry has been my long-term Rust development partner. We’ve built production cryptocurrency trading systems together — market-making and arbitrage on Binance Futures, Hyperliquid, Lighter, and Uniswap. These are systems handling real capital where bugs mean real losses, so code correctness and security are ingrained in how we work. Due to the commercially sensitive nature of quantitative trading, these projects live in private repositories — standard practice in this industry.

On the AI tooling question (CLAUDE.md in our repo): yes, we use AI assistants as part of our development workflow. We see this as a strength, not a weakness — AI-assisted fuzzing harness design and code path analysis significantly accelerates our work. The security judgment, methodology design, and responsible disclosure process are all human-driven.

Rather than profiles, I’d point to results: our deep fuzzing approach found a reportable security issue within the first day of deploying our new multi-layer harness methodology. That’s what matters.

2. OSS-Fuzz and M3 funding

Fair concern. We propose splitting M3 ($9,000):

  • $6,000 (fixed): Complete OSS-Fuzz integration PR (fuzz targets, Dockerfile, project.yaml), standalone CI fuzzing pipeline, curated seed corpus, and documentation. This is real engineering work regardless of Google’s decision.

  • $3,000 (conditional): Released upon Google’s acceptance.

Either way, we commit to maintaining continuous fuzzing infrastructure. If OSS-Fuzz declines, we’ll run equivalent continuous fuzzing on dedicated servers (cost ~$500/6 months). The Zcash community gets continuous fuzzing regardless — OSS-Fuzz acceptance just means Google subsidizes the compute.

3. Crash triage process

Here’s our workflow, which we’ve now battle-tested with a real finding:

Severity levels:

  • Critical: Remotely exploitable, affects consensus or network availability

  • High: Node crash or denial of service

  • Medium: Non-security logic errors

  • Low: Edge cases not affecting production

Process:

  1. Discovery — Fuzzer flags crash, triggering input automatically preserved

  2. Reproduction — Minimize test case (cargo fuzz tmin), confirm stable reproduction

  3. Classification — Determine severity, analyze attack reachability (can this be triggered remotely? via P2P? via RPC?)

  4. Reporting — Critical/High: private disclosure to ZF security team within 24 hours. Medium/Low: public GitHub issue

  5. Documentation — Each report includes: minimized input, stack trace, impact analysis, reachability assessment, and suggested fix

  6. Fix assistance — Patch suggestions + verification

  7. Disclosure — 90-day responsible disclosure window

We’ve now executed this entire pipeline end-to-end — from fuzzer discovery through reachability analysis to responsible disclosure — on a real finding. Not a hypothetical workflow anymore.

PoC progress:

Beyond the security finding (details embargoed), our Phase 1 numbers:

  • 95.6 million iterations across 6 targets, zero crashes in standard (Layer 1) fuzzing

  • Multi-layer deep fuzzing methodology: we go beyond “does it deserialize without panicking” to test property access, hash computation, consensus checks, and fee calculations on deserialized objects

  • Real mainnet data as seed corpus (1,565 transactions + 473 blocks from a fully-synced Zebra node)

  • Running across multiple machines (2-core GCP + 8-core dedicated server), with up to 52x performance scaling

The key insight: traditional deserialize-only fuzzing (Layer 1) ran 95M+ iterations and found nothing. Our multi-layer approach found a reportable issue within minutes of deployment. This is the methodological contribution we’re bringing.

Looking forward to the committee’s feedback.

3 Likes

Thanks @robustfengbin for the follow-up. I can confirm that the bug that you found and reported responsibly in Zebra was 1) serious and 2) remotely exploitable. Indeed this validates your approach, methodology and triage capabilities. Bravo!

I appreciate your commitment to M3 and doing the work to get GOOG to accept the project, as well as doing 6 months worth of fuzzing independently of acceptance into the GOOG program.

6 Likes

Thank you @alchemydc — this confirmation means a lot, both as validation of our methodology and as encouragement going forward.

The responsible disclosure process with ZF was smooth and professional. From report to hotfix, the turnaround was impressive, and we appreciate the team’s responsiveness.

Looking forward to continuing this collaboration. :folded_hands:

2 Likes

@thejohnnycrypto
Thanks, really appreciate this perspective.

I fully agree that fuzzing coverage on a consensus-critical node like Zebra is essential. The deserialization panic we found is exactly the kind of issue that can hide in edge cases and only surface under adversarial inputs.

Our goal with this proposal is not just to find isolated bugs, but to build a continuous fuzzing and triage pipeline that provides long-term security assurance for the ecosystem.

Really glad to see the community recognizing the importance of this work.

2 Likes

It’s not zero fuzzing! Ziggurat, which I did during my time at Equilibrium Labs fuzzed the network layer and found several critical-but-now-fixed vulns.

cc @olliten @JoakimEQ

9 Likes

Finding a critical bug was an excellent way to market your proposal :laughing: I support this!

3 Likes

@robustfengbin at the most recent meeting, ZCG voted to approve this proposal. Congratulations!

To keep the community informed, ZCG requests that you provide monthly updates via the forum in this thread.

Please check your forum inbox for a direct message from FPF with important next steps, including a link to the Milestone Payment Request Form and your unique validation code for submitting payment requests.

1 Like

Thank you ZCG for the approval! I’m excited to get started and grateful for the community’s trust.

I’ll begin work on Milestone 1 immediately and provide monthly progress updates in this thread as requested.

Looking forward to delivering meaningful security improvements for Zebra and the Zcash ecosystem.

2 Likes

M1 Month 1 — Coverage detail + disclosure follow-up

Two finer-grained pieces of evidence from the closed Month 1 window (2026-03-30 → 2026-04-30): a per-target coverage breakdown for the five fuzz harnesses, and a short coordinated-disclosure follow-up. M1 Month 2 (May) is the harden + ship window and is in progress; the M1 final delivery report will be posted ahead of the 2026-05-30 sign-off.


1. Coverage snapshot — 5 fuzz targets

Per-target line coverage at the close of Month 1, measured with cargo fuzz coverage against each target’s corpus and aggregated via llvm-cov report.

(Same data in text form for screen readers.)

Target Corpus files Key file Line coverage
block_deserialize 1,494 zebra-chain/src/block/serialize.rs 64.38%
block_deep_fuzz 353 zebra-chain/src/block/serialize.rs 64.38%
p2p_message_parse 283 zebra-network/src/protocol/external/codec.rs 32.85%
p2p_deep_fuzz 344 zebra-network/src/protocol/external/codec.rs 35.48%
addr_message_fuzz 16 zebra-network/src/protocol/external/addr/v1.rs corpus expansion in flight

Block deserialization — coverage on key zebra-chain files:

File Lines Line coverage
zebra-chain/src/transaction/serialize.rs 828 83.45%
zebra-chain/src/sapling/output.rs 123 83.74%
zebra-chain/src/orchard/action.rs 62 87.10%
zebra-chain/src/sapling/spend.rs 147 74.83%
zebra-chain/src/orchard/note/nullifiers.rs 22 77.27%
zebra-chain/src/serialization/compact_size.rs 116 81.03%
zebra-chain/src/serialization/zcash_deserialize.rs 106 57.55%
zebra-chain/src/serialization/zcash_serialize.rs 96 53.12%
zebra-chain/src/serialization/read_zcash.rs 36 50.00%
zebra-chain/src/block/serialize.rs 160 64.38%

A note on block/serialize.rs: the residual ~36% un-covered region is composed mostly of the CountedHeader serialize/deserialize impls (used by P2P “headers”-only messages, not on the block_deserialize fuzz path) and the SerializedBlock conversion impls (the serialize direction; this target only exercises deserialize). These regions are unreachable from Block::zcash_deserialize regardless of corpus or fuzz duration — they need a separate ser-direction target, which is a Month 2 hardening candidate.

The block target reaches deep into transaction-internal deserialization paths because mainnet blocks embed real V5 / V4 transactions. That’s why transaction/serialize.rs, sapling/output.rs, and orchard/action.rs all sit at 80%+ line coverage from the block target alone.


2. Coordinated disclosure update

While preparing M1 Month 2 work, we identified a panic in Zebra’s V6 transaction hash path that was reachable through a recently exercised code path. We submitted the report through the standard GitHub Security Advisory workflow on the Zebra repository. The Zebra Foundation security team triaged the report promptly, then converted it to a public tracking issue with High severity and the appropriate C-bug / S-needs-triage labels. We would like to thank @conradoplg and the Zebra Foundation security team for the rapid and constructive triage — initial submission to public tracking inside one working day.


3. Where this leaves M1 going into the final stretch

Month 2 is the consolidation window:

  • Hardening of the existing targets and corpus seeding for the queued candidates
  • Initial CI smoke scaffold (M2 deliverable preparation)
  • Upstream re-baselining
  • M1 final delivery report ahead of the 2026-05-30 sign-off

All scope and quality remain anchored to the proposal verbatim deliverables and acceptance criteria. Thanks again to ZCG, the Zebra Foundation, and the broader Zcash community for the support and the responsive coordination on disclosure.

2 Likes