# gosentry

[[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

```bash
./bin/go test -fuzz=FuzzHarness \
    --focus-on-new-code=false \
    --catch-races=true \
    --catch-leaks=true
```

```bash
go test -fuzz=FuzzTarget --generate-coverage
```

The harness:

```go
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 [[toolbox/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.
