Map

gosentry

Toolbox toolboxgolangrustfuzzingsecuritywatchlistGo / Rustsee repo โ†ณ show in map Markdown
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-on flag for codebases that log errors instead of panicking
  • CLI: extends go test -fuzz with 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.