
Security-oriented Go toolchain, focused on state-of-the-art fuzzing capabilities.
gosentry is a security-focused fork of the Go toolchain, integrating numerous features for state-of-the-art fuzzing campaigns on Go codebases. If you were using go test -fuzz before, you should use gosentry as a replacement.
It comes with various fuzzing improvements and bug detectors that are not present natively in the Go toolchain. See TLDR; below. You can also read the associated blog article here.
TLDR (features and options):
struct inputs directly (no custom parser needed). Add seeds with f.Add(Input{N: 7, S: "hi"}) then f.Fuzz(func(t *testing.T, in Input) { ... }).X + Y - Z can become X / U + Z - 14 instead of X + Yè - Zcd src && ./make.bash # Produces `../bin/go`. See `GOFLAGS` below.
[!TIP] Contributor docs: read
docs/gosentry/index.mdfor a code map, recommended dev loop, CI entrypoints and benchmark scripts. This fork uses the Pull GitHub App to open and auto-merge PRs fromgolang/go:masterintomaster, ensuring we never stay behind Go toolchain latest updates.
Go’s native fuzzing (go test -fuzz=...) only supports a small set of scalar types as fuzz parameters ([]byte, string, numbers, ...). In gosentry, you can also fuzz composite types built from those scalars: structs, arrays, slices, and pointers.
This is useful when your code naturally takes structured inputs and you don’t want to build a custom encoder/decoder just to seed and mutate the corpus.
See test/gosentry/examples/multiargs and test/gosentry/examples/composite for examples.
type Input struct {
Data []byte
S string
N int
OK bool
}
func FuzzStructInput(f *testing.F) {
// Seed the initial corpus with a Go struct (gosentry feature).
f.Add(Input{Data: []byte("A"), S: "B", N: 7, OK: true})
f.Fuzz(func(t *testing.T, in Input) {
if in.OK && in.N == 1337 && in.S == "BOOMMOOB" && bytes.Equal(in.Data, []byte("A")) {
t.Fatalf("boom")
}
})
}
f.Add) and struct fuzzing work (the glue made)Go’s native fuzzer cannot fuzz a struct value directly (it only knows how to mutate a small list of scalar types). gosentry adds a small glue layer: when your fuzz target uses composite types (like Input), gosentry fuzzes a single []byte behind the scenes. On every execution, it decodes those bytes into your struct (field-by-field, recursively for slices/arrays/pointers) and then calls your f.Fuzz callback with the decoded value. The same encoding is used for seeds, so f.Add(Input{...}) becomes an encoded []byte corpus entry that the fuzzer can reuse and mutate like any other seed.
Fuzzers (including LibAFL) mutate raw bytes, so we want a decoder that can turn any byte slice into "some" struct value and keep going. JSON/gob would reject most random inputs (bad for coverage), and they also don’t populate unexported fields, while fuzzing often benefits from breaking invariants. This custom format is small, fast, deterministic, and tolerant to malformed data.
Under the hood, this uses gosentry’s own simple binary format (not gob, not JSON). The code lives in src/testing/libafl.go:
libaflMarshalInputs / libaflAppendValuelibaflUnmarshalArgs / libaflDecodeValueEncoding rules (high level):
bool: 1 byte (0 or 1)int/uint are 8 bytes)float32 = 4 bytes, float64 = 8 bytes)string: uvarint(len) then raw string bytes[]byte: uvarint(len) then raw bytesuvarint(len) then each element encoded0 = nil, 1 = present) then the pointed valueThis work is inspired from the previously developed go-panikint. It adds overflow/underflow detection for integer arithmetic operations and (optionally) type truncation detection for integer conversions. When overflow or truncation is detected, a panic with a detailed error message is triggered, including the specific operation type and integer types involved.
Arithmetic operations: Handles addition +, subtraction -, multiplication *, and division / for both signed and unsigned integer types. For signed integers, covers int8, int16, int32. For unsigned integers, covers uint8, uint16, uint32, uint64. The division case specifically detects the MIN_INT / -1 overflow condition for signed integers. int64 and uintptr are not checked for arithmetic operations.
Type truncation detection: Detects potentially lossy integer type conversions. Covers all integer types: int8, int16, int32, int64, uint8, uint16, uint32, uint64. Excludes uintptr due to platform-dependent usage. This is disabled by default.
Overflow detection is enabled by default. To disable it, add GOFLAGS='-gcflags=-overflowdetect=false' before your ./make.bash. You can also enable truncation issues checker with: -gcflags=-truncationdetect=true
This feature patches the compiler SSA generation so that integer arithmetic operations and integer conversions get extra runtime checks that call into the runtime to panic with a detailed error message when a bug is detected. Checks are applied using source-location-based filtering so user code is instrumented while standard library files and dependencies (module cache and vendor/) are skipped.
You can read the associated blog post about it here.
Add a marker on the same line as the operation or the line immediately above to suppress a specific report: