Go Security
Dependency Management
- Use Go modules for all dependency management
- The
go.sumchecksum database provides assurance against module mutation - Pin dependency versions, including transitive modules
- Run
govulncheckregularly to scan for known vulnerabilities in dependencies
Input Validation
- Validate all user input using Go native packages (
strconv,regexp) or third-party validators like go-playground/validator - Never trust input from external sources without validation
XSS Prevention
Use html/template (not text/template) for rendering HTML. It applies contextual autoescaping for HTML, CSS, JavaScript, and URL contexts.
goname := r.FormValue("name") tmpl := template.Must(template.ParseGlob("page.html")) data["Name"] = name err := tmpl.ExecuteTemplate(w, "page", data)
Use nosurf for CSRF prevention in HTTP handlers.
SQL Injection Prevention
Use parameterized queries. In Go, statements are prepared on the DB, not the connection:
gocustomerName := r.URL.Query().Get("name") db.Exec("UPDATE creditcards SET name=? WHERE customerId=?", customerName, 233)
When using db.Query() with string formatting, sanitize all input first.
Cryptography
- Use Go's standard
cryptoandgolang.org/x/cryptopackages - Do not implement custom cryptographic algorithms
- Use well-established algorithms (AES-GCM, ChaCha20-Poly1305, Ed25519)
HTTPS and TLS
Enforce HTTPS with HSTS headers and explicit TLS server configuration:
gow.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
goconfig := &tls.Config{ServerName: "yourServiceName"}
Always encrypt in-transit communication, even for internal services.
unsafe and cgo
unsafe Package
- The
unsafepackage bypasses Go's type system; subtle mistakes are common - Avoid
unsafeunless there is no alternative (low-level system calls, performance-critical FFI) - Verify safe usage with Go's vet tooling
cgo
Avoid cgo when possible. Known issues:
- Breaks Go's cross-compilation
- Increases binary size and reduces portability
- cgo calls are significantly slower than native Go calls
- Puts Go's concurrency model at risk
- May break static binary linking
Error Handling and Logging
- Handle every error explicitly (
if err != nil) - Never log secrets, tokens, API keys, or PII
- Sanitize data before including it in log output
- Do not expose internal error details in user-facing responses
nil Pointer Safety
When unmarshalling JSON into structs with pointer fields, unset pointers remain nil. Dereferencing them causes a panic:
gotype Foo struct { Bar *Bar } var f Foo json.Unmarshal([]byte(`{"other":"data"}`), &f) // f.Bar is nil -- accessing f.Bar.Field will panic
Always check pointer fields for nil before dereferencing.
Tooling
| Tool | Purpose |
|---|---|
| govulncheck | Scan dependencies for known vulnerabilities |
| golangci-lint | Aggregated linter collection |
| gosec | Go security checker |
Implementation Checklist
- Go modules are used with
go.sumintegrity checking -
govulncheckruns in CI - All user input is validated before use
-
html/templateis used for HTML rendering (nottext/template) - SQL queries use parameterized statements
- Standard
cryptopackages are used (no custom crypto) - HSTS is set and TLS is configured with explicit
ServerName -
unsafeandcgousage is justified, minimized, and reviewed - Errors are handled explicitly; no secrets in logs or error responses
- Pointer fields are checked for nil before dereferencing


