This project provides a setup for fuzzing golang binaries using LibAFL.
By leveraging Go’s native libFuzzer-compatible instrumentation (sancov_8bit
), we enable advanced fuzzing capabilities beyond Go’s built-in fuzzing support.
- In-process fuzzing for maximum performance.
- Coverage-guided fuzzing with comparison tracing support for guided mutation.
- Interoperability with Go via Foreign Function Interface (FFI).
Across all our 24-hour benchmarks, GoLibAFL consistently achieved higher code coverage than existing Go fuzzing solutions. Below is the result for the prometheus target.
- Go 1.18 or later (recommended: latest version)
- Rust (nightly toolchain recommended for optimizations)
- Cargo and Rust toolchain installed
-
Clone the repository:
git clone <repo-url> cd <repo-name>
-
Define your golang harness (see below)
-
Define the harness location with the environement variable
HARNESS
:export "HARNESS=harnesses/prometheus"
-
Build and run the Rust-based LibAFL fuzzer:
cargo run --release -- fuzz
or
docker build --build-arg HARNESS="harnesses/prometheus" -t golibafl . docker run -v ./output:/golibafl/output golibafl
Implement your harness in the LLVMFuzzerTestOneInput
function, which will be used by LibAFL:
func LLVMFuzzerTestOneInput(data *C.char, size C.size_t) C.int {
// `data` should be converted to the type you need and passed as input
input := C.GoBytes(unsafe.Pointer(data), C.int(size))
// function to be fuzzed, i.e `parse`
mylib.parse(input)
}
For an example setup, refer to our harness template.
To execute the harness with a specific input, run:
cargo run -- run -i <path_to_input>
If no input path is provided, the default input directory is ./input
.
To see the available command-line options for a subcommand, use:
cargo run -- fuzz --help
cargo run -- run --help
- Use Rust nightly toolchain for optimized memory mapping.
- Upgrade Go to at least version 1.23 to avoid
cgo
stack bound performance issues.
- Fix garbage collector limitations
This project is licensed under the Apache 2.0 License.