Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Fuzzing

Meridian’s parsers are continuously fuzz-tested using cargo-fuzz with LLVM’s libFuzzer. The fuzzing harness uses coverage-guided mutation, structure-aware input generation, and security invariant assertions.

Running the Fuzzer

# Requires nightly Rust
rustup toolchain install nightly

# Run a specific target (runs until stopped)
cargo +nightly fuzz run http1_request

# Run with HTTP dictionary (faster exploration)
cargo +nightly fuzz run http1_request -- -dict=fuzz/dictionaries/http.dict

# Run for a fixed time
cargo +nightly fuzz run http1_request -- -max_total_time=3600

# Run all targets
for t in http1_request http1_structured body_framing header_smuggling \
         path_normalize config_toml chunked_body; do
  cargo +nightly fuzz run $t -- -max_total_time=3600
done

Fuzz Targets

TargetTechniqueSpeedWhat It Tests
http1_requestRaw bytes~200K/secHTTP/1.1 parser never panics
http1_structuredStructure-aware~79K/secDeep parser states via arbitrary
body_framingStructure-aware~67K/secCL+TE smuggling detection
header_smugglingDifferential~62K/secAdversarial header combos with invariant checks
path_normalizeRaw bytes~142K/secIdempotence, no traversal, no double slashes
config_tomlRaw UTF-8~48K/secTOML deserializer never panics
chunked_bodyRaw bytes (async)~26K/secDechunker respects size limits

Techniques

Coverage-Guided Mutation

libFuzzer tracks which code branches are covered by each input. Inputs that reach new branches are kept and mutated further. This systematically explores the parser’s state space rather than generating random noise.

Structure-Aware Fuzzing

The http1_structured and body_framing targets use the arbitrary crate to generate structured HTTP requests. The fuzzer mutates structured fields (methods, headers, versions) independently while maintaining HTTP-like syntax, reaching deeper parser states faster than raw byte mutation.

Security Invariant Assertions

The header_smuggling and body_framing targets embed security invariants as assertions:

#![allow(unused)]
fn main() {
// If both Content-Length and Transfer-Encoding are present, MUST reject
if has_cl && has_te {
    assert!(result.is_err(), "SMUGGLING: CL+TE accepted!");
}
}

If the fuzzer finds an input that violates these invariants, it’s a real security bug.

HTTP Dictionary

The fuzz/dictionaries/http.dict file contains HTTP protocol tokens (methods, headers, delimiters, smuggling payloads) that seed the fuzzer’s mutation engine for faster exploration of HTTP-specific code paths.

Bugs Found

The fuzzer has found and fixed:

  1. Integer overflow in chunked body size check — A chunk with hex size ffffffffffffffff caused body.len() + chunk_size to wrap around usize, bypassing the max body size limit. Fixed with overflow-safe arithmetic.

Crash Artifacts

When a crash is found, the input is saved to fuzz/artifacts/<target>/crash-<hash>. To reproduce:

cargo +nightly fuzz run chunked_body fuzz/artifacts/chunked_body/crash-<hash>