atheris-python-fuzzing
Author and run Atheris - Google's Python coverage-guided fuzzer built on libFuzzer. Covers pip installation, atheris.Setup + atheris.Fuzz invocation, TestOneInput(data: bytes) target signature, FuzzedDataProvider for structured input, instrument_imports() / instrument_func decorators for coverage instrumentation, and libFuzzer-passthrough flags (-atheris_runs, -max_total_time, -dict). Use for fuzzing Python libraries - also supports CPython native-extension fuzzing.
Install with skills.sh (any agent)
npx skills add testland/qa --skill atheris-python-fuzzingatheris-python-fuzzing
Overview
Atheris (per github.com/google/atheris (opens in new window)) supports both pure-Python and native-extension targets (CPython C extensions).
For sanitiser pairing on native extensions, see sanitiser-integration-reference; for corpus discipline see corpus-management-reference.
When to use
Authoring
Install
pip install atherisPer the Atheris README, prebuilt wheels include libFuzzer for pure-Python fuzzing. Native-extension fuzzing may require building from source so the Clang and libFuzzer versions match.
Basic fuzz target
# fuzz_parser.py
import sys
import atheris
with atheris.instrument_imports():
from my_library import parser
def TestOneInput(data):
parser.parse(data)
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()Per Atheris README:
Coverage instrumentation
Atheris needs to instrument the modules under test:
with atheris.instrument_imports():
from my_library import parser, decoderThe instrument_imports() context manager monkey-patches the import system so subsequent imports are coverage-instrumented. Module-level imports above this context manager are NOT instrumented - the fuzzer is blind to their code.
Alternative: per-function instrumentation:
import my_library
my_library.parser.parse = atheris.instrument_func(my_library.parser.parse)Or instrument-all (heavyweight):
atheris.instrument_all()FuzzedDataProvider
For structured input, use the Python equivalent of libFuzzer's helper:
def TestOneInput(data):
fdp = atheris.FuzzedDataProvider(data)
port = fdp.ConsumeInt(4) # signed 4-byte int
is_https = fdp.ConsumeBool()
host = fdp.ConsumeUnicode(64) # up to 64 chars
body_size = fdp.ConsumeIntInRange(0, 1024)
body = fdp.ConsumeBytes(body_size)
parser.parse_request(host, port, is_https, body)Per Atheris README, the provider exposes ConsumeInt, ConsumeUnicode, ConsumeFloat, ConsumeBool, PickValueInList, and related methods.
Running
Basic run
python fuzz_parser.pyAtheris by default runs indefinitely. Pass libFuzzer-style flags:
python fuzz_parser.py -max_total_time=300 corpus/The trailing directory is the corpus (read + write). Subsequent directories are read-only seeds.
Common flags
Per Atheris README, all libFuzzer flags pass through:
| Flag | Effect |
|---|---|
-max_total_time=N | Stop after N seconds |
-atheris_runs=N | Run N iterations then stop (also enables coverage report) |
-dict=path | Use dictionary file |
-seed=N | Random seed |
-runs=N | libFuzzer runs (use -atheris_runs for Atheris-specific) |
Coverage report
python fuzz_parser.py -atheris_runs=100000 corpus/
# At end: prints coverage statisticsReproducing a crash
python fuzz_parser.py crash-<sha1>
# Same crash with full tracebackParsing results
Python tracebacks instead of sanitiser reports (unless instrumenting a CPython extension built with ASan):
[+] Loading binary contents from crash-abc123
=== Uncaught Python exception: ===
ValueError: invalid syntax
Traceback (most recent call last):
File "fuzz_parser.py", line 12, in TestOneInput
parser.parse(data)
File "/path/my_library/parser.py", line 47, in parse
return json.loads(text)
...Map the traceback to a bug spec via bug-report-from-failure (in the qa-defect-management plugin).
CI integration
- uses: actions/setup-python@v6
with: { python-version: '3.12' }
- run: pip install atheris
- name: Smoke fuzz (3 min)
run: timeout 180 python fuzz_parser.py -max_total_time=180 corpus/ || true
- uses: actions/upload-artifact@v4
with:
name: atheris-crashes
path: crash-*Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Module imports above instrument_imports() | Coverage signal absent for those modules | Always import via with atheris.instrument_imports(): ... |
No exception handling in TestOneInput | Expected exceptions (ValueError on bad input) count as crashes | Catch expected exceptions; only let unexpected ones propagate |
| Pure-Python target without instrumentation | Coverage is blind; fuzzer flailing | Always instrument |
Missing atheris.Fuzz() call | Fuzz loop never starts | Always end with atheris.Fuzz() |
| Treating every traceback as a bug | Many tracebacks are spec-compliant (raising ValueError on invalid input is correct) | Use assert for invariants; let spec-defined exceptions through |
| Native extension without ASan | C bugs silent (segfault crashes Python interpreter) | Build CPython + extension with ASan for native fuzzing |
Limitations
References
Related skills
afl-plus-plus
Author and run AFL++ - out-of-process coverage-guided fuzzer (a community fork of Google's original AFL with improved mutations and instrumentation). Covers afl-cc / afl-clang-fast instrumented build, afl-fuzz invocation, parallel master/slave (-M / -S), dictionary support (-x), QEMU mode (-Q) for binaries without source, output structure (queue / crashes / hangs), crash minimisation (afl-tmin), corpus minimisation (afl-cmin), crash filename triage, and CI integration. Use for fuzzing standalone binaries (file processors, command-line tools) where libFuzzer's in-process model doesn't fit; for cross-fuzzer corpus strategy see corpus-management-reference.
cargo-fuzz-rust
Author and run cargo-fuzz - Rust fuzzing via libFuzzer with cargo integration. Covers `cargo install cargo-fuzz`, `cargo fuzz init` + `cargo fuzz add {target}` for harness scaffolding, the `fuzz_target!` macro for entry-point declaration, the `Arbitrary` trait for structured input mutation, and `cargo fuzz run` invocation. Requires Rust nightly. Use for fuzz testing Rust libraries - cargo-fuzz wraps libFuzzer with native Rust ergonomics.
corpus-management-reference
Pure-reference catalog of fuzz-corpus management practices. Defines what a corpus is (seed corpus + evolved corpus saved by the fuzzer), corpus directory layout per libFuzzer / AFL++ / Go native / cargo-fuzz / OSS-Fuzz, the canonical crash-artefact naming (crash-{sha1} / leak-{sha1} / timeout-{sha1}), seed corpus construction strategies (sample-from-prod, sample-from-test-fixtures, from-spec-keywords), corpus minimisation, dictionary files, and the OSS-Fuzz integration corpus sync. Use as the corpus-discipline reference when building a fuzz target or maintaining a long-running fuzz campaign.
crash-triage-reference
Pure-reference catalog for manually triaging individual fuzzer crash artifacts - reading ASan, UBSan, and MSan output; classifying findings as LIKELY-EXPLOITABLE, MEDIUM, or BENIGN; deduplicating by stack-hash; and minimizing reproducers with -minimize_crash. Use when you need to understand what a specific crash means, build exploitability intuition, or manually work a small set of findings. For automated bulk triage across a full artifact directory, run automated findings triage instead.
fuzz-tool-selector
Routes a fuzz-target authoring task to the right fuzzer for the detected language and build type. Decision tree: C/C++ → libfuzzer-cpp + afl-plus-plus; Rust → cargo-fuzz-rust (or libfuzzer-cpp via FFI); Go → go-native-fuzzing; Python → atheris-python-fuzzing; JVM → jazzer-jvm-fuzzing; closed-source binary → afl-plus-plus in QEMU mode; mature open-source project → ossfuzz-integration. Use when a project needs coverage-guided fuzzing and no fuzzer has been chosen for its language or toolchain yet.
go-native-fuzzing
Author and run Go's native fuzzing (Go 1.18+) - coverage-guided fuzzing built into the standard testing package via FuzzXxx functions. Covers f.Add seed-corpus declaration, f.Fuzz callback signature with typed parameters, testdata/fuzz/{FuzzXxx}/ directory layout for seeds + regression cases, the -fuzz flag for `go test`, and CI integration via short smoke runs. Use for fuzz testing Go libraries - Go's native approach integrates seamlessly with standard `go test` rather than requiring a separate toolchain like AFL++.
jazzer-jvm-fuzzing
Author and run Jazzer - Code Intelligence's JVM coverage-guided fuzzer built on libFuzzer. Covers Maven / Gradle / standalone JAR installation, the @FuzzTest annotation (JUnit 5 integration), typed parameter mutation (String, primitives, byte[]), built-in JVM sanitisers (SSRF / path traversal / OS command injection / deserialization gadget / ReDoS), and the JAZZER_FUZZ=1 env var to switch between regression and fuzzing modes. Use for fuzz testing Java / Kotlin libraries - particularly effective against parsing, deserialization, and HTTP-handling code.
libfuzzer-cpp
Author and run LLVM libFuzzer for C/C++ - in-process coverage-guided fuzzing. Covers harness authoring (LLVMFuzzerTestOneInput entry point), build with -fsanitize=fuzzer,address,undefined, runtime flags (-max_total_time, -runs, -dict, -fork, -workers), corpus + crash-artefact handling, and CI integration. Use for libraries / parsers / decoders in C/C++ where in-process fuzzing of a function is the right scope. Compose with ASan + UBSan from sanitiser-integration-reference and corpus discipline from corpus-management-reference.
ossfuzz-integration
Author and submit a project to Google OSS-Fuzz - the open-source continuous fuzzing service that runs libFuzzer / AFL++ / Honggfuzz campaigns on Google infrastructure 24x7. Covers the project.yaml + Dockerfile + build.sh contract, the $OUT/$WORK conventions, supported languages + sanitisers, seed-corpus + dictionary submission, the OSS-Fuzz Build Status dashboard, and the disclosure SLA (issues filed in Monorail with 90-day deadline). Use to offload long-running fuzz campaigns to dedicated infrastructure rather than self-hosting.
sanitiser-integration-reference
Pure-reference catalog of compiler sanitisers used with fuzz testing - AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan), MemorySanitizer (MSan), ThreadSanitizer (TSan), and LeakSanitizer (LSan). Explains what each detects, compatibility (can ASan + UBSan combine? - yes; ASan + MSan? - no), build flags, runtime options (ASAN_OPTIONS / UBSAN_OPTIONS env vars), and the typical ~2x slowdown per ASan. Use to pick the right sanitiser per fuzz target, configure the build, and interpret crash reports.