gosentry
- title
- gosentry
- type
- toolbox
- summary
- Fork of the Go toolchain that runs standard testing.F fuzz harnesses through a LibAFL+Nautilus engine โ struct-aware, grammar-aware, race/leak/overflow detection
- tags
- golang, rust, fuzzing, security, watchlist
- language
- Go / Rust
- license
- see repo
- created
- 2026-05-12
- updated
- 2026-05-12
trail-of-bits forked the Go toolchain so that go test -fuzz=FuzzX runs through a Rust libafl-based runner instead of Go's built-in fuzzer. The author writes the harness using the regular testing.F API; gosentry intercepts the f.Fuzz callback, builds a Go archive with libFuzzer-style entry points, and runs it in-process.
The motivation, in one sentence: Go's stdlib fuzzer can't solve path constraints, can't take structured input, can't drive a grammar, and silently ignores Go-specific bug classes (integer overflows, goroutine leaks, races, infinite loops). gosentry plugs those four gaps without making the harness writer learn a new framework. See gosentry-go-fuzzing-fork for the writeup.
What it does differently from stock go test -fuzz
- Engine: LibAFL (Rust) instead of Go's coverage-guided mutator
- Input types: structs, slices, arrays, pointers (see structure-aware-fuzzing) โ not just primitives
- Grammar mode: Nautilus-driven generation from JSON-array production rules (see grammar-based-fuzzing)
- Bug detection: compiler-inserted integer overflow checks, go-panikint truncation checks, the Go race detector, goleak goroutine-leak detection, timeout detection, plus a
--panic-onflag for codebases that log errors instead of panicking - CLI: extends
go test -fuzzwith flags like--catch-races=true --catch-leaks=true --focus-on-new-code=false --generate-coverage
Usage
./bin/go test -fuzz=FuzzHarness \
--focus-on-new-code=false \
--catch-races=true \
--catch-leaks=true
go test -fuzz=FuzzTarget --generate-coverage
The harness:
func FuzzExample(f *testing.F) {
f.Add(exampleValue)
f.Fuzz(func(t *testing.T, input []byte) {
TargetFunction(input)
})
}
is byte-identical to what you'd write for stock Go fuzzing. The mechanical difference is the toolchain you invoke.
What it found early
Differential fuzzing across implementations of the same protocol spec, mostly in the Ethereum L2 space:
- Optimism/Kona: unknown batch type โ DoS panic
- Optimism: Brotli channel disagreement between Kona and op-node
- Optimism: frame parsing mismatch against spec
- Revm: failed-deposit nonce bump bug, causing state-root divergence
Constraints
- Toolchain fork โ must track upstream Go releases on an ongoing basis
- Rust toolchain required in the build environment for the LibAFL runner
- Significant runtime overhead with all detectors on (race + leak + overflow + coverage) โ tune per campaign
- The fuzzed binary is not the production binary; nothing here replaces production hardening
Watchlist
This is on watchlist โ a one-day-old fork-and-rewrite from a single security firm. Watching for upstream-Go-tracking cadence, contributor count outside Trail of Bits, whether the LibAFL integration survives Go's quarterly toolchain churn, and whether the bug counts in real campaigns hold up across other Go ecosystems besides crypto/L2.