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.
  • govulncheck is praised because it checks whether vulnerable symbols are actually reachable, reducing noise vs CVE-only scanners.
  • golangci-lint and 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 error values:
    • 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., tar path 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 for loop 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.