Comprehensive fuzzing infrastructure for cachekit's ByteStorage and encryption modules, designed to detect security vulnerabilities before production deployment.
This fuzzing suite provides 14 fuzz targets covering:
- ByteStorage attacks: Corrupted envelopes, integer overflow, checksum collision, format injection, empty data edge cases
- Encryption attacks: Key derivation, nonce reuse, truncated ciphertext, AAD injection, large payloads
- Integration testing: Layered security (compression + encryption)
Security Model: Fail-closed - all malicious inputs must be safely rejected without panics or undefined behavior.
# Install cargo-fuzz (libfuzzer-based)
cargo install cargo-fuzz
# Install AFL++ (optional, for mutation-based fuzzing)
cargo install cargo-afl# Quick smoke test (60s per target, ~14min total)
cd rust && make fuzz-quick
# Fuzz single target for development
cd rust && make fuzz-target TARGET=byte_storage_corrupted_envelope
# Deep fuzzing (8 hours per target, production validation)
cd rust && make fuzz-deep TARGET=encryption_key_derivation
# Generate coverage report
cd rust && make fuzz-coveragebyte_storage_corrupted_envelope.rs
- Attack: Malformed MessagePack
StorageEnvelopedeserialization - Validates: Safe rejection of corrupted serialization without panics
- Tests: Invalid MessagePack structures, truncated data, type confusion
byte_storage_integer_overflow.rs
- Attack: Decompression bomb via oversized
original_size(u32::MAX, boundary cases) - Validates: Size limit enforcement, integer overflow protection
- Tests: u32::MAX, MAX_UNCOMPRESSED_SIZE ± 1, suspicious compression ratios
byte_storage_checksum_collision.rs
- Attack: Data corruption with manipulated xxHash3-64 checksums
- Validates: Integrity verification detects mismatches
- Tests: Bit flips, truncation, zero checksums, partial corruption
byte_storage_empty_data.rs
- Attack: Inconsistent envelope state (empty data + non-zero size)
- Validates: Envelope consistency checks
- Tests: Empty compressed_data with original_size=1000, vice versa, both empty
byte_storage_format_injection.rs
- Attack: Malicious format identifiers (path traversal, nulls, control chars)
- Validates: Format string treated as opaque identifier
- Tests: "../../../etc/passwd", null bytes, CRLF, Unicode attacks, 10KB+ strings
encryption_key_derivation.rs
- Attack: Malicious tenant IDs in key derivation
- Validates: Deterministic key derivation without crashes
- Tests: Nulls, path traversal, Unicode, empty strings, 10KB+ length
encryption_nonce_reuse.rs
- Attack: Nonce uniqueness verification (encrypt same plaintext 100x)
- Validates: Cryptographic randomness, no ciphertext repetition
- Tests: Multiple encryptions with same key+plaintext produce distinct outputs
encryption_truncated_ciphertext.rs
- Attack: Partial/incomplete ciphertext (truncated auth tags)
- Validates: Authentication failure detection
- Tests: Truncation at nonce, ciphertext body, auth tag boundaries
encryption_aad_injection.rs
- Attack: Additional Authenticated Data with nulls, control chars, Unicode
- Validates: AAD cryptographic binding (wrong AAD = decrypt fails)
- Tests: Null bytes, control characters, Unicode, 1-bit AAD modification
encryption_large_payload.rs
- Attack: Production-scale payloads (1MB, 10MB, 100MB)
- Validates: Performance and correctness at scale
- Tests: Large allocations, memory efficiency, no artificial 4KB limits
integration_layered_security.rs
- Attack: Corruption at multiple layers (plaintext → compression → encryption)
- Validates: Proper error attribution per layer
- Tests: Pre-compression corruption, post-compression corruption, ciphertext tampering
rust/fuzz/corpus/
├── byte_storage/
│ ├── valid_envelopes/ # Valid MessagePack envelopes
│ ├── corrupted_envelopes/ # Known corruption patterns
│ ├── size_edge_cases/ # MIN, MAX, boundary sizes
│ └── format_strings/ # Valid + malicious format identifiers
├── encryption/
│ ├── key_material/ # Valid 32-byte keys, edge cases
│ ├── tenant_ids/ # Realistic + malicious tenant IDs
│ ├── aad_patterns/ # Normal + injected AAD
│ └── ciphertext_samples/ # Valid + truncated ciphertext
└── integration/
└── layered_data/ # Compressed-then-encrypted samples
# Generate initial corpus from test fixtures
cd rust/fuzz && ./scripts/generate_corpus.sh
# Minimize corpus (deduplicate, reduce size)
cd rust/fuzz && ./scripts/minimize_corpus.sh
# Validate corpus integrity (< 10MB total)
cd rust/fuzz && ./scripts/validate_corpus.shCorpus Size Limit: Total corpus should remain under 10MB for fast CI smoke tests.
.github/workflows/fuzz-smoke.yml runs on every pull request:
- 60 seconds per target (~14 minutes total)
- Catches fuzzing regressions before merge
- Uploads crash artifacts on failure
# Simulate CI smoke tests locally
cd rust && make fuzz-quickRun before releases or periodically:
# 8 hours per target (production-grade validation)
cd rust && make fuzz-deep TARGET=encryption_key_derivation# Triage crashes: deduplicate, minimize, generate regression tests
cd rust/fuzz && ./scripts/triage_crashes.sh
# Output: deduplicated_crashes.txt with stack traces and minimized inputsWorkflow:
- Find all crash artifacts in
artifacts/ - Extract and hash stack traces for deduplication
- Minimize unique crashes with
cargo fuzz cmin - Generate regression test templates (
#[test] #[should_panic])
# Reproduce specific crash
cargo fuzz run byte_storage_corrupted_envelope artifacts/crash-xyz
# Minimize crash input
cargo fuzz cmin byte_storage_corrupted_envelopeAFL++ provides mutation-based fuzzing complementary to libfuzzer's coverage-guided approach:
# Build AFL++ target
cd rust && cargo afl build --features afl
# Run AFL++ fuzzer
cd rust && make fuzz-afl TARGET=byte_storage_corrupted_envelope# Generate LLVM coverage report
cd rust && make fuzz-coverage
# View HTML report
open rust/fuzz/coverage/html/index.htmlNote: Fuzzing coverage measures code paths explored, not test quality. Use this to identify untested paths.
"cargo-fuzz not found"
cargo install cargo-fuzz"Corpus too large (>10MB)"
cd rust/fuzz && ./scripts/minimize_corpus.sh"Fuzzing too slow"
- Reduce input size limits in targets (e.g.,
if data.len() > 1024 { return; }) - Use
fuzz-quickfor rapid iteration - Check for expensive operations in hot paths
"Crash can't be reproduced"
# Ensure same libfuzzer version
cargo fuzz run TARGET artifacts/crash-xyz -- -exact_artifact_path=artifacts/crash-xyz- Start small: Use
fuzz-quickto verify targets compile and run - Parallelize: Run multiple targets simultaneously on multi-core machines
- Seed wisely: Good corpus seeds improve coverage 10-100x faster
- Monitor coverage: Use
fuzz-coverageto identify unexplored paths
Each target focuses on one specific attack vector for maximum coverage depth:
- Deep exploration of single attack surface (vs shallow exploration of many)
- Clear failure attribution (which attack succeeded?)
- Independent corpus optimization per attack type
- Easier crash triage and minimization
All fuzz targets enforce fail-closed behavior:
- Malicious input → Safe rejection (
Err(...), no panic) - Panic = Test failure (fuzzer reports bug)
- Undefined behavior = Instant failure (sanitizers catch)
- Libfuzzer (default): Coverage-guided, fast iteration, LLVM sanitizers
- AFL++: Mutation-based, finds different bug classes, mature tooling
- Both engines share corpus for cross-pollination
When adding new fuzz targets:
- Follow naming convention:
<module>_<attack_vector>.rs - Add target to
Cargo.toml[[bin]] section - Create corpus subdirectory with
.gitkeep - Document attack vector in this README
- Add target to
FUZZ_TARGETSlist inrust/Makefile - Verify with
make fuzz-target TARGET=your_new_target