Safeguard
Application Security•

How do you decode untrusted data safely in Go?

Go's gob package is not hardened against hostile input. Use JSON into typed structs, reject unknown fields, and cap request size before decoding.

Safeguard Security Team
4 min read

In Go, decode untrusted data with a plain format such as JSON into typed structs, reject unknown fields, and limit input size before decoding. Avoid gob for data from outside your trust boundary: its own documentation says it is not designed to be hardened against adversarial inputs.

What does the gob documentation warn about?

The encoding/gob package says in its Security section: "This package is not designed to be hardened against adversarial inputs, and is outside the scope of https://go.dev/security/policy." It adds that care should be taken when decoding gob data from untrusted sources, which may consume significant resources, and that the decoder does only basic sanity checking on decoded input sizes, with limits that are not configurable.

Go's gob is used for things like RPC arguments, for example in net/rpc. If you expose such an endpoint to the internet, you accept those limits. Keep gob for traffic between components you control and authenticate.

What risks remain with a plain format?

The gob page names resource consumption as a concern with hostile input. The same applies to any decoder: oversized bodies, deeply nested values and unexpected shapes. A format change does not remove the need for limits and validation. We did not find a Go specific list of deserialization attack patterns in the sources we read, so this post sticks to what those docs say.

How should you decode JSON?

Decode into a struct with the fields you expect. Two details from the encoding/json docs matter.

By default, object keys with no matching struct field are ignored. If you want the request rejected, use Decoder.DisallowUnknownFields, which returns an error when the destination is a struct and the input has keys that match no exported field.

If you decode into an interface value, JSON numbers become float64, objects become map[string]any and arrays become []any. Decoding into any hands you a loose shape that your code then has to validate by hand. A typed struct pushes that work to the decoder. Decoder.UseNumber stores numbers as Number rather than float64 when you must use interface values, which avoids precision loss on large integers.

What does a safe handler look like?

A constructed example: an HTTP handler for a settings update. It wraps the request body in a size limiter, creates a JSON decoder, turns on unknown field rejection, decodes into a struct with a small set of fields, and then checks each field's range and format. A field that grants a role is simply absent from the struct, so a client who sends it gets an error and not a silent privilege change.

Size limiting is your job. The standard library offers http.MaxBytesReader for this, though we did not fetch its page, so confirm the details in the net/http docs.

What to do

  1. Grep for encoding/gob and find where input comes from outside your control.
  2. Replace gob on public boundaries with JSON or another plain format, or authenticate the sender first.
  3. Decode into typed structs and call DisallowUnknownFields on the decoder.
  4. Cap request body size before decoding.
  5. Validate each decoded field for range, length and format.
  6. Keep privileged fields out of request structs, so clients cannot set them.
  7. Add a test that sends oversized and unexpected input and expects a clean error.
  8. Run govulncheck on the module so a vulnerable decoder in a dependency is caught.

Safeguard can scan Go modules for known issues and use reachability analysis to show whether vulnerable code is actually called.

Quick check

Is gob safe for internal services?

It is designed for exchanging values between a trusted encoder and decoder. Its docs say it is not hardened against adversarial input, so keep it behind authentication and network controls.

Does DisallowUnknownFields validate my data?

No. It rejects keys that match no struct field. You still have to check the values.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.