---
title: "Segurança Go: seis padrões sutis para revisar no código"
url: "https://golang.com.br/novidades/seguranca-go-code-review/"
markdown_url: "https://golang.com.br/novidades/seguranca-go-code-review.MD"
description: "Segurança Go vai além de scanners: veja seis padrões sutis de revisão de código que podem gerar falhas reais em produção."
date: "2026-06-15"
author: "Go Brasil"
---

# Segurança Go: seis padrões sutis para revisar no código

Segurança Go vai além de scanners: veja seis padrões sutis de revisão de código que podem gerar falhas reais em produção.


TL;DR: a elttam publicou uma nova lista de notas de revisão de código em Go com problemas que passam fácil por scanners automáticos: overflow silencioso, `httputil.ReverseProxy` com `Director`, ponteiros compartilhados de `url.URL`, bytes nulos atravessando cgo, `MarshalJSON` que falha por causa do receiver e APIs JSON vulneráveis a CSRF. O valor do texto está menos em uma grande novidade da linguagem e mais em transformar detalhes conhecidos da biblioteca padrão em uma checklist prática para revisar serviços Go em produção.

## Por que isso importa

Go costuma dar uma sensação saudável de segurança: tipos fortes, runtime com memória gerenciada, biblioteca padrão conservadora e ferramentas como `go test`, `govulncheck` e race detector. Isso ajuda muito, mas não elimina vulnerabilidades que nascem de semântica sutil, contrato de API mal entendido ou interação com navegadores, proxies e código C.

O artigo [Golang code review notes II](https://www.elttam.com/blog/golang-code-review-notes-ii), de Zoltan Madarassy e Alex Brown, é interessante justamente por focar nesses pontos de revisão manual. Não é uma lista genérica de OWASP. São casos em que o código compila, passa em testes comuns e ainda assim pode criar bypass de autenticação, vazamento entre requisições ou parsing ambíguo.

Para quem mantém APIs em Go, a leitura combina bem com uma revisão periódica de segurança: buscar padrões no repositório, confirmar hipóteses com testes pequenos e trocar APIs antigas por alternativas mais explícitas quando elas existem.

## Overflow e truncamento continuam sendo problemas

Go não entra em pânico quando um inteiro estoura. Em código de aplicação, isso muitas vezes é irrelevante. Em parsers, serializadores e protocolos binários, pode virar vulnerabilidade.

Um padrão perigoso é transformar o resultado de `len`, que é `int`, em um tipo menor sem checar limite:

```go
func writeLength(buf *bytes.Buffer, payload []byte) {
    n := len(payload)
    if n > math.MaxUint32 {
        return
    }
    binary.Write(buf, binary.BigEndian, uint32(n))
    buf.Write(payload)
}
```

A parte importante não é o exemplo em si, mas a pergunta de revisão: algum tamanho controlado por entrada externa é convertido para `uint16`, `uint32` ou `int32` antes de ser gravado, alocado ou usado como limite? Se sim, a checagem precisa aparecer antes do cast, não depois.

## ReverseProxy: prefira Rewrite para headers sensíveis

O ponto mais prático para serviços web é `httputil.ReverseProxy`. O artigo destaca um detalhe perigoso: quando `Director` adiciona headers sensíveis, headers hop-by-hop podem ser removidos depois. Um atacante pode abusar do header `Connection` para fazer o proxy descartar algo que o backend esperava receber, como `X-Internal-Auth` ou `X-Forwarded-Proto`.

Em revisões, procure construções como:

```go
proxy := &httputil.ReverseProxy{
    Director: func(r *http.Request) {
        r.Header.Set("X-Internal-Auth", token)
    },
}
```

Para código novo, a direção recomendada é usar `Rewrite` e `httputil.ProxyRequest`, que deixam mais claro o que acontece com a requisição de entrada e a requisição de saída. Isso reduz a chance de misturar headers controlados pelo cliente com headers de confiança adicionados pela infraestrutura.

## Ponteiros de URL e estado compartilhado

`url.Parse` retorna `*url.URL`. Copiar a variável copia o ponteiro, não a estrutura. Em um handler HTTP, isso pode criar vazamento entre requisições se uma URL global for reutilizada e modificada.

```go
var baseRedirect, _ = url.Parse("https://app.example/callback")

func handler(w http.ResponseWriter, r *http.Request) {
    u := *baseRedirect
    q := u.Query()
    q.Set("request_id", r.URL.Query().Get("id"))
    u.RawQuery = q.Encode()
    http.Redirect(w, r, u.String(), http.StatusFound)
}
```

O detalhe é o `u := *baseRedirect`: ele copia o valor apontado. Em código real, a revisão deve procurar `u := baseRedirect` seguido de mutações como `u.RawQuery = ...`, `u.Path = ...` ou alterações em `u.User`.

## Fronteiras com C e bytes nulos

Strings Go podem conter `\x00`. APIs em C, por outro lado, frequentemente tratam byte nulo como fim da string. Esse desencontro pode gerar bypass quando uma validação em Go vê `admin\x00` como diferente de `admin`, mas uma camada C de autenticação, LDAP, PAM ou driver nativo interpreta apenas `admin`.

A regra de revisão é simples: antes de passar dados externos para cgo ou bibliotecas que cruzam para C, rejeite bytes nulos nos campos relevantes. Isso vale especialmente para nomes de usuário, caminhos, identificadores, filtros LDAP e credenciais.

## JSON: receiver de MarshalJSON e CSRF

Outro ponto fácil de perder envolve `encoding/json`. Se `MarshalJSON` foi definido apenas em `*T`, serializar um `T` por valor pode não aplicar a lógica de mascaramento esperada. Para tipos usados em redaction, teste os dois caminhos: `json.Marshal(v)` e `json.Marshal(&v)`.

O artigo também reforça que API JSON não é automaticamente imune a CSRF. Se o endpoint aceita corpo sem exigir `Content-Type: application/json`, usa cookies com `SameSite=None` e decodifica apenas o primeiro valor JSON deixando bytes extras no corpo, um formulário malicioso pode chegar mais longe do que deveria. Para serviços HTTP, vale combinar validação de `Content-Type`, política correta de cookies, proteção de origem quando aplicável e leitura completa do corpo.

## Como transformar em checklist

Uma boa forma de usar o artigo é rodar buscas pequenas no repositório e abrir revisões focadas:

- `httputil.ReverseProxy` com `Director` que adiciona headers de confiança;
- casts de `len(...)` ou valores externos para inteiros menores;
- `*url.URL` global ou compartilhado sendo mutado em handlers;
- `MarshalJSON` com receiver de ponteiro em tipos que escondem dados sensíveis;
- entrada externa atravessando cgo sem bloqueio de `\x00`;
- endpoints JSON autenticados por cookie sem checagem rígida de origem e conteúdo.

Isso complementa, não substitui, ferramentas automáticas. Scanners encontram CVEs conhecidas e alguns padrões estáticos; revisão humana ainda é melhor para entender confiança entre camadas.

## Saiba mais

- [Golang code review notes II](https://www.elttam.com/blog/golang-code-review-notes-ii)
- [Go Security: Boas Práticas de Segurança](/tutoriais/go-security/)
- [Go 1.25: Novidades e Recursos](/blog/go-1-25/)
