gosec-go
Configures and runs gosec - Go-only SAST covering 40+ rule IDs (G101 hardcoded creds, G104 unhandled errors, G304 path traversal, G401 weak crypto, G601 memory aliasing) via Go AST + SSA taint tracking; `gosec ./...` scan, `#nosec G404 -- justification` suppression, `--fmt sarif|json|junit-xml|html`, golangci-lint integration. Use for a focused Go SAST wired into golangci-lint / CI. Go-only: for Python use bandit-python, for cross-language pattern SAST use semgrep-rules; to merge gosec findings with other scanners into one gate use multi-tool-finding-triage - not this for non-Go code.
Install with skills.sh (any agent)
npx skills add testland/qa --skill gosec-gogosec-go
Overview
Per github.com/securego/gosec (opens in new window):
gosec is the Go-specific SAST. It "performs static code analysis by scanning the Go AST and SSA code representation" and supports "taint analysis tracking data flow from user inputs to dangerous functions" per gs-gh (opens in new window).
The taint analysis distinguishes gosec from regex-based linters - it tracks input flow through method chains, which catches injection patterns linters miss.
When to use
How to use
Step 1 - Install
Per gs-gh (opens in new window):
go install github.com/securego/gosec/v2/cmd/gosec@latestFor pinned versions in CI:
go install github.com/securego/gosec/v2/cmd/gosec@v2.20.0Docker:
docker pull securego/gosec
docker run --rm -v "$PWD:/code" securego/gosec ./code/...Step 2 - Basic recursive scan
Per gs-gh (opens in new window):
gosec ./...Common variations:
gosec -severity=high ./... # only HIGH severity
gosec -confidence=high ./... # only HIGH confidence
gosec -exclude=G104 ./... # skip "unhandled errors" rule
gosec -include=G101,G102 ./... # only run specific rulesStep 3 - Rule ID catalog
gosec ships 40+ rule IDs (G101 hardcoded creds, G104 unhandled errors, G304 path traversal, G401 weak crypto, G601 memory aliasing, and more). The full lookup table - every ID and its meaning - lives in references/rule-catalog.md.
Full current list at runtime: gosec -list-rules.
Step 4 - Output formats
Per gs-gh (opens in new window):
gosec -fmt sarif -out results.sarif ./...
gosec -fmt json -out results.json ./...
gosec -fmt junit-xml -out results.xml ./...
gosec -fmt html -out results.html ./...
gosec -fmt text -out results.txt ./...
gosec -fmt yaml -out results.yaml ./...For multi-scanner triage integration, use JSON.
Step 5 - False-positive triage (MANDATORY)
Per gs-gh (opens in new window) the canonical inline suppression syntax:
// #nosec G404 -- justification textFormat: #nosec [RuleList] [-- Justification].
Three suppression layers:
| Mechanism | Example | When to use |
|---|---|---|
Per-line #nosec | // #nosec G101 -- test fixture; not deployed to prod | Single-line exception with justification |
Per-rule list #nosec | // #nosec G104,G115 -- intentional in this fast-path | Multi-rule single-line |
-exclude= flag | gosec -exclude=G104 ./... | Project-wide rule disable (CI flag) |
-confidence= filter | gosec -confidence=high ./... | Triage workflow: only high-confidence first |
Justification template (mandatory in code):
// #nosec G401 -- Reason: legacy MD5 required for vendor-mandated checksum format
// Reviewer: alice@example.com (2026-05-15)
// Expires: 2026-12-15
hash := md5.Sum(data)Bandit-style cadence: every quarter, grep for #nosec patterns lacking -- Reason: and flag for review.
Step 6 - golangci-lint integration
Most Go teams run gosec via golangci-lint (the universal linter runner) rather than directly:
# .golangci.yml
linters:
enable:
- gosec
linters-settings:
gosec:
excludes:
- G104 # unhandled errors (often noise)
severity: medium
confidence: medium
config:
G306: "0644" # default file perm thresholdgolangci-lint run ./...This is the recommended pattern - golangci-lint handles parallelism, caching, and unified output across multiple linters.
Step 7 - CI integration
Standalone:
jobs:
gosec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
with: { go-version: '1.22' }
- uses: securego/gosec@master
with:
args: -fmt sarif -out gosec.sarif ./...
- uses: github/codeql-action/upload-sarif@v3
if: always()
with: { sarif_file: gosec.sarif }Via golangci-lint (preferred):
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v5
with: { go-version: '1.22' }
- uses: golangci/golangci-lint-action@v6
with:
version: latestStep 8 - Custom rules via Go templates
Unlike Semgrep / CodeQL, gosec doesn't have a custom-rule DSL - adding new rules requires writing Go code in gosec/rules/ and contributing upstream OR forking. For most teams, leverage the 40+ built-in rules + suppressions.
Worked example
A Go microservice needs to clear a security review. Run gosec -severity=high -confidence=high ./...; gosec reports a G401 on a md5.Sum(data) call and a G104 on an unchecked w.Write return.
Re-run gosec -fmt sarif -out gosec.sarif ./...; the SARIF now reports zero HIGH findings, and the golangci-lint gate from Step 6 passes in CI.
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
#nosec without rule ID | Suppresses ALL rules on that line | // #nosec G401 (specific, Step 5) |
#nosec without -- Justification | No audit trail | Required template (Step 5) |
Skip -confidence= filter | LOW confidence drowns the team | -confidence=high for triage (Step 2) |
| Run gosec separately from golangci-lint | Two linters with different config | golangci-lint integration (Step 6) |
| Exclude G104 globally | Loses entire "unhandled errors" coverage | Per-call // #nosec G104 -- intentional |
Limitations
References
gosec rule ID catalog
View source (opens in new window)gosec rule ID catalog
Per github.com/securego/gosec (opens in new window) the common rule IDs. This is a lookup table for interpreting a finding's rule ID; the authoritative current list is emitted at runtime by gosec -list-rules.
| Rule | Description |
|---|---|
| G101 | Hardcoded credentials |
| G102 | Bind to all interfaces (0.0.0.0) |
| G103 | Audit unsafe block (use of unsafe package) |
| G104 | Unhandled errors |
| G106 | SSH InsecureIgnoreHostKey |
| G107 | URL with potential SSRF |
| G201 | SQL query construction by string concat |
| G202 | SQL query construction by string format |
| G204 | Subprocess launched with variable |
| G301 | Poor file permissions on directory |
| G302 | Poor file permissions on file |
| G303 | Predictable temp-file name |
| G304 | File path traversal vulnerabilities |
| G305 | File traversal in tar archive |
| G401 | Weak cryptographic algorithms |
| G402 | TLS InsecureSkipVerify |
| G403 | RSA key length too short |
| G404 | Insecure random number generation |
| G501-G505 | Insecure crypto primitives (DES, MD5, RC4, SHA1) |
| G601 | Implicit memory aliasing in for-range |
| G602 | Slice bounds out of range |
Prefix families at a glance: G1xx credential / injection / unsafe surface, G2xx SQL and subprocess construction, G3xx file and path handling, G4xx crypto and TLS misuse, G5xx insecure crypto primitives, G6xx Go memory and slice hazards.
Full list: gosec subcommand gosec -list-rules.
Related skills
bandit-python
Configures and runs Bandit - Python-only SAST covering 60+ rule IDs across 7 categories (B1xx-B7xx: misc, app, crypto, imports, injections, XSS); `bandit -r .` scan, `--severity-level` + `--confidence-level` filtering, `# nosec`/`# nosec B404` per-line and per-rule suppression, `pyproject.toml [tool.bandit]` config. Use for a focused, low-overhead Python SAST in pre-commit / CI. Python-only: for Go use gosec-go, for cross-language pattern SAST use semgrep-rules; to merge Bandit findings with other scanners into one gate use multi-tool-finding-triage - not this for non-Python code.
codeql-queries
Configures and runs GitHub CodeQL - semantic-database SAST with queries written in the CodeQL declarative query language; supports `codeql database create` (per-language) + `codeql database analyze` with --format=sarif; ships query packs (`codeql/javascript-queries`, `codeql/python-queries`, `codeql/java-queries`, `codeql/go-queries`, etc.); integrates with GitHub Code Scanning via SARIF upload; suppression via inline comment + sarif-filter + Security-tab dismissal. Use when the team uses GitHub-hosted repos and needs deep semantic SAST beyond pattern matching (cross-file taint flows, dataflow analysis).
eslint-security-rules
Configures and runs `eslint-plugin-security` (14 detect-* rules covering injection, path traversal, ReDoS, unsafe buffers, and bidi trojan-source) plus `eslint-plugin-no-unsanitized` (DOM XSS via `innerHTML`, `outerHTML`, `document.write`, `insertAdjacentHTML`) as the JS/TS first-party SAST layer; covers flat config setup, per-rule suppression with justification templates, SARIF output via `@microsoft/eslint-formatter-sarif` for GitHub Code Scanning upload, and CI gating on ESLint exit code 1. Use when the project is JS or TS and needs an in-process security lint pass without a separate SAST server.
multi-tool-finding-triage
Merges two or more security scanner reports into one gate. Use when you need a single BLOCK or PASS decision from multiple scanners instead of reading N separate reports. Normalizes each report into one common finding format (a canonical `Finding`), deduplicates on a per-domain key while recording which scanners agree (`caught_by` consensus), validates a waiver (finding-suppression) file, rejecting any missing `expires:` / `approved_by:` / `reason:` or expired, enriches CVE findings with EPSS (exploit-probability) and CISA KEV (known-exploited catalog), then applies a `fail_on` severity threshold to emit BLOCK or PASS plus a bucketed pull-request comment. Works across static (SAST), dynamic (DAST), secret, dependency (SCA), container, and IaC scanners. To run a single scanner instead use semgrep-rules, codeql-queries, bandit-python, or gosec-go; this runs after them to merge output - the cross-scanner gate, not a single-scanner wrapper.
pmd-apex-rules
Runs PMD's built-in Apex security ruleset (`category/apex/security.xml`) against Salesforce Apex source to detect injection, privilege-escalation, cryptographic, and XSS vulnerabilities; configures custom rulesets for regulated-industry Apex codebases; emits SARIF for GitHub Code Scanning upload; integrates `pmd check` as a PR-blocking CI gate. Use when the codebase contains Salesforce Apex and the team needs SAST coverage for ApexSOQLInjection, ApexCRUDViolation, ApexSharingViolations, or the full 10-rule security category.
semgrep-rules
Configures and runs Semgrep - pattern-based SAST across 30+ languages with the Semgrep Registry rulesets (`p/owasp-top-ten`, `p/default`, `auto`) plus custom YAML rules; integrates `semgrep ci` for PR-blocking gates with `--baseline-commit` diff-aware scanning, per-finding inline `nosemgrep` suppressions, `--exclude` / `--include` path filters, output formats (`--json` / `--sarif` / `--gitlab-sast` / `--junit-xml`), and severity filter (INFO/WARNING/ERROR). Use when the user runs Semgrep, asks about pattern rules, or needs a low-friction SAST gate without semantic-DB setup.
sonarqube-rules
Configures and runs SonarQube / SonarCloud - multi-language SAST + Quality Gate platform with built-in Sonar Way rule profiles + custom rule plugins; integrates `sonar-scanner` with `sonar-project.properties` config; supports Quality Gate definitions including new-code-period blocking, branch + PR analysis, and per-issue suppression via `// NOSONAR` comment or `@SuppressWarnings("squid:RULE_ID")` annotation. Use when the user runs SonarQube Community / Developer / Enterprise edition or SonarCloud, or needs a multi-language SAST + code-quality platform with persistent issue tracking.