Go compiles fast, ships as a single static binary, and rules out most of the memory-corruption bugs — buffer overflows, use-after-free, dangling pointers — that keep C and C++ security teams busy. Go 1.22, released in February 2024, even closed the decade-old for-loop variable capture footgun that caused subtle goroutine bugs in nearly every Go codebase written before it. But Go is not a security silver bullet. The public Go module proxy now indexes more than 1.6 million packages, and a single go get can pull in a dependency graph almost nobody audits by hand. Between 2022 and 2024, the Go standard library itself shipped fixes for an HTTP/2 denial-of-service flaw (CVE-2023-39325), a CPU-exhaustion bug in net/http (CVE-2022-27664), and an IP-parsing error in net/netip (CVE-2024-24790). This cheat sheet covers the vulnerability classes that actually show up in Go services, the tools that catch them, and the CVEs worth patching today.
What are the most common vulnerabilities found in Go codebases?
The most common issues in Go codebases aren't memory-safety bugs — they're vulnerable dependencies, hardcoded credentials, and injection flaws in the application code written on top of Go's safe runtime. Go's own vulnerability database, maintained at pkg.go.dev/vuln since 2021, has grown to several hundred cataloged advisories, and the majority sit in third-party modules rather than the standard library. Static analysis surveys of open-source Go projects consistently turn up the same top offenders: CWE-798 (hardcoded credentials) in config files and test fixtures, CWE-89 (SQL injection) from fmt.Sprintf-built queries instead of parameterized database/sql calls, and CWE-918 (server-side request forgery) in services that proxy user-supplied URLs. A representative example: a Go microservice that accepts a callback_url parameter and passes it directly to http.Get() without an allowlist can be tricked into reaching a cloud metadata endpoint like 169.254.169.254, exposing instance credentials. None of these require a language-level memory bug — they're design mistakes that show up regardless of what language wrote them.
How do you catch vulnerable Go dependencies before they ship?
You catch vulnerable Go dependencies by running govulncheck against your module graph, because unlike a plain go.sum diff or a generic SCA scan, it's call-graph-aware and only flags advisories in code paths your binary actually reaches. Govulncheck was built by the Go team and hit stable release in June 2023; it cross-references your imports against the official Go vulnerability database rather than a generic CVE feed, which cuts a huge amount of noise from transitive dependencies you import but never call. A concrete case worth knowing: CVE-2022-32149 in golang.org/x/text/language let a single crafted Accept-Language header drive CPU usage to 100% by triggering catastrophic parsing behavior — a one-line fix in x/text v0.3.8 (September 2022) resolved it, but any service still pinned to an older x/text version remains exposed. Pair govulncheck with go list -m all in CI and enforce GOFLAGS=-mod=readonly so builds fail on an unverified go.sum rather than silently re-resolving dependencies.
Which Go standard library CVEs should you patch right now?
At minimum, patch for the HTTP/2 Rapid Reset vulnerability (tracked as CVE-2023-39325 in Go's net/http and golang.org/x/net/http2), fixed in Go 1.20.10 and 1.21.3 on October 10, 2023, since it let attackers open and immediately cancel thousands of HTTP/2 streams per connection to exhaust server resources — the same class of bug that hit Cloudflare, Google, and AWS the same month. Also confirm you're past Go 1.21.11 / 1.22.4 (June 2024), which fixed CVE-2024-24790, a bug in net/netip that mishandled IPv4-mapped IPv6 addresses in a way that could bypass IP-based access controls. If you build on Windows, check for CVE-2023-45283 and CVE-2023-45284, path-traversal issues in path/filepath and os that let a crafted relative path escape a restricted directory — both fixed in Go 1.20.11 and 1.21.4 (November 2023). Standard library CVEs are easy to miss because teams patch application dependencies religiously but forget that the Go toolchain version itself is a supply chain component; go version -m on your compiled binaries will tell you exactly which runtime shipped in each artifact.
How should Go services handle secrets, tokens, and credentials?
Go services should pull secrets from a dedicated secrets manager — Vault, AWS Secrets Manager, or GCP Secret Manager — at runtime, never from source code or committed config, because a statically compiled Go binary embeds any hardcoded string directly into the artifact where a simple strings command against the binary recovers it. Environment variables are a step up from hardcoding but still leak through process listings, crash dumps, and container inspection APIs, so treat them as a fallback rather than the destination. This isn't theoretical: GitHub's push protection, turned on by default for all public repositories in 2023, blocked more than one million secret leaks in its first year of general availability, and a large share were AWS keys and database connection strings committed by mistake in exactly this kind of Go service config. Run gitleaks or trufflehog in pre-commit hooks and CI, and rotate any credential immediately if it lands in git history — deleting the file doesn't remove it from prior commits.
Does Go's memory safety mean you can skip static analysis?
No — Go's memory safety only removes one bug class, while logic flaws, data races, and unsafe escapes still require static analysis to catch. The -race flag and go vet cover a narrow slice of problems (data races and a handful of suspicious constructs), but neither one flags a SQL injection, an SSRF, or a goroutine leak that slowly exhausts memory under load. Tools like gosec implement rule sets from G101 (hardcoded credentials) through G115 (integer overflow conversion) specifically because Go's compiler won't stop you from writing db.Query("SELECT * FROM users WHERE id = " + userInput) or from wrapping unsafe C code behind cgo, which reintroduces every memory-safety risk Go otherwise avoids. If your services use unsafe.Pointer or cgo anywhere in the dependency tree — common in high-performance serialization libraries and some crypto bindings — treat that code with the same scrutiny you'd give a C file, because Go's safety guarantees stop at the import "C" boundary.
How do you prevent SSRF and injection bugs in Go microservices?
You prevent SSRF and injection bugs in Go by validating and allowlisting every outbound request target before it reaches net/http.Client, and by using parameterized queries through database/sql instead of building SQL strings with fmt.Sprintf or string concatenation. Go makes injection just as easy as any other language does — db.Exec(fmt.Sprintf("DELETE FROM sessions WHERE token='%s'", token)) is exploitable the same way a raw PHP or Node query is, and database/sql's placeholder syntax (? for MySQL, $1 for Postgres) exists specifically to avoid it. For SSRF, block requests to RFC 1918 private ranges, 169.254.169.254, and ::1/localhost at the HTTP client's DialContext, not just at input validation, since redirects and DNS rebinding can route around a URL string check performed before the request is made. Webhook receivers, image-proxy services, and PDF-generation endpoints that fetch a user-supplied URL are the most common place this shows up in Go codebases, because they're built quickly and rarely get a second security pass once they work.
How Safeguard Helps
Safeguard maps these Go-specific risks directly to your running services instead of treating every advisory in govulncheck's output as equally urgent. Reachability analysis traces whether a vulnerable function in a flagged dependency is actually invoked by your call graph, so a golang.org/x/net CVE in code you never call doesn't page your on-call engineer at 2 a.m. Griffin, Safeguard's AI analysis engine, reads the vulnerable code path and your surrounding application logic to explain exploitability in plain language and generate an auto-fix pull request that bumps the dependency and re-runs your test suite. Safeguard also generates and ingests SBOMs for your Go binaries — resolving the full module graph, including replace directives and vendored code — so you have an auditable record of exactly what shipped in every release, not just what's declared in go.mod.