DevSecOps

GoSec Static Analysis for Go: Practical Security Scanning

GoSec finds security issues in Go source code. Here is how to get the most out of it without fighting false positives all day.

James
Security Analyst
5 min read

GoSec (originally Gas) is the most widely used security scanner for Go source code. It inspects the Go AST for patterns associated with security vulnerabilities: hardcoded credentials, SQL injection, insecure TLS configurations, weak cryptography, and more.

Go's design philosophy already eliminates certain vulnerability classes. There is no eval(), the type system prevents many injection patterns, and the standard library's crypto packages default to secure configurations. But Go developers can still write insecure code, and GoSec is built to catch the patterns that come up most often.

What GoSec Detects

GoSec organizes its rules by ID. The most important ones for typical Go applications:

G101: Hardcoded credentials. Detects string literals assigned to variables with names suggesting they contain credentials (password, secret, token, api_key). This catches the most common form of secret leakage.

G104: Unhandled errors. Go's error handling pattern requires explicit checking. Ignoring errors from security-sensitive functions (file operations, network calls, crypto operations) can mask failures that compromise security.

G107: URL provided to HTTP request as taint input. Flags cases where a variable (potentially user-controlled) is passed directly as a URL to an HTTP client. This can enable server-side request forgery (SSRF).

G201-G204: SQL injection. Detects string concatenation or fmt.Sprintf used to build SQL queries. Go's database/sql package supports parameterized queries, so there is no reason to build queries through string manipulation.

G301-G307: File permissions and path handling. Catches overly permissive file permissions, path traversal risks, and insecure temporary file creation.

G401-G407: Weak cryptography. Flags use of DES, RC4, MD5, and SHA1 for security purposes. Also detects insecure random number generation using math/rand instead of crypto/rand.

G501-G505: Import blocklist. Flags imports of packages known to have security issues, such as net/http/cgi which has a known header injection vulnerability.

G601: Implicit aliasing in for loops. Before Go 1.22, loop variable capture was a common source of bugs. While Go 1.22 fixed the language default, GoSec still flags the pattern for codebases that might run on older versions.

Configuration

GoSec accepts configuration through command-line flags or a configuration file. The most useful configuration options:

gosec -include=G101,G201,G202,G203,G204,G301,G401,G501 ./...

The -include flag runs only the specified rules. This is useful when you want to focus on high-confidence rules and ignore noisier ones.

Alternatively, use -exclude to disable specific rules:

gosec -exclude=G104 ./...

G104 (unhandled errors) is the most commonly excluded rule because it produces high volumes of findings. Many ignored errors are intentionally ignored (closing a response body, for example). If you exclude G104, complement it with errcheck or go vet for error handling coverage.

For SARIF output (useful for GitHub Security tab integration):

gosec -fmt=sarif -out=results.sarif ./...

False Positive Management

GoSec supports inline suppression via comments:

password := getPasswordFromVault() // #nosec G101 -- loaded from vault at runtime

The #nosec directive with a rule ID suppresses only that specific rule. Without a rule ID, it suppresses all GoSec checks for that line -- avoid this pattern.

Track your suppressions. A script that counts #nosec directives by rule ID across the codebase reveals which rules generate the most false positives. If a rule has dozens of suppressions and few true positives, it is not earning its keep.

Integration With golangci-lint

Most Go projects use golangci-lint as their lint aggregator. GoSec integrates as a golangci-lint plugin, which simplifies configuration:

linters:
  enable:
    - gosec
linters-settings:
  gosec:
    excludes:
      - G104
    config:
      G301:
        mode: strict

This approach lets you manage GoSec alongside other linters with a single configuration file and a single CI step.

What GoSec Misses

GoSec is a pattern matcher. It does not perform taint analysis or track data flows across function boundaries. If user input passes through three function calls before reaching a SQL query, GoSec will not flag it.

GoSec does not understand frameworks. It cannot tell that a particular ORM parameterizes queries automatically or that a web framework sanitizes template output.

GoSec does not check dependencies. Vulnerabilities in your imported packages are invisible to GoSec. Use govulncheck (the official Go vulnerability checker) for dependency-level vulnerability detection.

GoSec does not check for business logic flaws, authentication bypasses, or authorization failures. These require manual review or more sophisticated analysis tools.

Complementary Tools

govulncheck is the official Go vulnerability scanner. It checks your dependencies against the Go vulnerability database and, importantly, reports whether your code actually calls the vulnerable functions -- not just whether the vulnerable package is in your dependency tree.

staticcheck catches additional correctness and performance issues that can have security implications.

go vet is built into the Go toolchain and catches issues like incorrect printf format strings and unreachable code.

Semgrep provides custom rule authoring for Go-specific patterns that GoSec does not cover.

How Safeguard.sh Helps

Safeguard.sh extends your Go security coverage beyond what GoSec provides by monitoring your module dependencies for known vulnerabilities and generating comprehensive SBOMs for your Go projects. While GoSec catches security anti-patterns in your source code, Safeguard.sh watches the supply chain -- alerting you when a Go module in your dependency tree is affected by a new vulnerability and mapping the impact across all your projects that use that module.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.