Writing secure Go code
Security tooling for Go
- People highlight
gosec,go vet,go test -race,govulncheck,golangci-lint,capslock, and Semgrep as key tools. govulncheckis praised because it checks whether vulnerable symbols are actually reachable, reducing noise vs CVE-only scanners.golangci-lintand linters in general are seen as important for catching ignored errors and some race patterns.
Is Go a “secure language”?
- Broad agreement: Go is relatively secure compared with C/C++ and similar to other modern, memory-safe languages.
- Common web vulns (SQLi, XSS, authz bugs, DOS) are possible in any language; Go is no exception.
- Go is said to “lack some footguns” (no
eval, no implicit shelling out, safer templates, harder-to-misuse deserialization), but still gives you “knives” to hurt yourself. - Some argue meaningful security differences between modern high-level languages are small; others say ecosystem, tooling, and culture still matter.
Error handling and footguns
- Major debate over Go’s explicit
errorvalues:- Critics: easy to forget to check errors; needs third‑party linters; leads to real security bugs (e.g., ignored permission checks).
- Defenders: idioms and linting mitigate this; most mistakes crash (fail-closed) rather than silently grant access.
- Comparisons drawn to exceptions and sum types in other languages (Java, Rust, Haskell) that make ignoring errors harder.
- Many wish for syntactic sugar (
?‑style chaining), but attempts so far are seen as unsatisfactory or dangerous.
Concurrency, data races, and memory safety
- Go is officially treated as memory-safe but only if there are no data races.
- Discussion of how races on multiword values (interfaces, slices) can break memory safety; contrived demos exist.
- Some argue this is mostly theoretical for security: few or no real-world exploits, and the race detector works well.
- Others say UB from races is inherently concerning, especially as Go adoption and attacker interest grow.
Standard library, dependencies, and ecosystem
- Many praise Go’s rich stdlib (HTTP, crypto, JSON, SQL, RNG, etc.), which reduces dependency sprawl and simplifies upgrades.
- Others argue stdlib stability freezes insecure defaults (e.g.,
tarpath issues, HTTP/TLS timeouts), creating “security traps” that are hard to evolve. - Comparing ecosystems:
- Go is seen as easier to maintain across versions than heavy Java/Spring or JS/Node dependency trees.
- Rust’s smaller stdlib but evolving crates; JS/TS culture criticized for fragile, sprawling dependency graphs.
Language evolution and new pitfalls
- New 3‑clause
forloop semantics in Go 1.22 are called a “footgun” by some; others consider the concern overblown and mostly theoretical so far. - Generics spark mixed reactions:
- Pro: enable reusable containers/iterators and nicer APIs.
- Con: iterator/generic-heavy code is harder to read, raising cognitive load compared with older, simpler Go.