gosec

repository·master·Indexed 27 days ago

https://github.com/securego/gosec

A security checker for Go source code that inspects AST and SSA code representations to detect security vulnerabilities. It provides a CLI tool, a GitHub Action, and a Go package for integration with tools like Bazel's nogo. Features include support for multiple output formats (SARIF, JSON, etc.), AI-powered vulnerability auto-fixing, and the ability to suppress false positives via inline comments or configuration files.

Tokens
12.7K
Snippets
36
Records
100
Agent score
90%

What's inside gosec

  1. Create taint analysis rules

    master

    Taint analyzers track data flow from untrusted Sources to dangerous Sinks.

    Implementation Steps

    1. Create an analyzer file in analyzers/ containing a taint.Config (sources, sinks, and optional sanitizers) and a constructor that returns taint.NewGosecAnalyzer(...).
    2. Register the analyzer in analyzers/analyzerslist.go.
    3. Add sample programs in testutils/.
    4. Add the analyzer test in analyzers/analyzers_test.go using the runner function.

    Taint Configuration Reference

    Sources

    • Package: import path (e.g., "net/http")
    • Name: type or function name (e.g., "Request", "Getenv")
    • Pointer: true for pointer types (e.g., *http.Request)
    • IsFunc: true if the source is a function returning tainted data

    Sinks

    • Package: import path
    • Receiver: method receiver type (empty for package functions)
    • Method: method name
    • Pointer: whether receiver is a pointer
    • CheckArgs: optional integer slice of argument indexes to inspect. If omitted, all args are inspected.

    Sanitizers

    Sanitizers break taint flow. They use the same configuration fields as Sinks (Package, Receiver, Method, Pointer).

    package analyzers
    
    import (
    	"golang.org/x/tools/go/analysis"
    
    	"github.com/securego/gosec/v2/taint"
    )
    
    func NewVulnerability() taint.Config {
    	return taint.Config{
    		Sources: []taint.Source{
    			{Package: "net/http", Name: "Request", Pointer: true},
    			{Package: "os", Name: "Args", IsFunc: true},
    		},
    		Sinks: []taint.Sink{
    			{Package: "dangerous/package", Method: "DangerousFunc"},
    		},
    	}
    }
    
    func newNewVulnAnalyzer(id string, description string) *analysis.Analyzer {
    	config := NewVulnerability()
    	rule := NewVulnerabilityRule
    	rule.ID = id
    	rule.Description = description
    	return taint.NewGosecAnalyzer(&rule, &config)
    }
  2. Configure gosec for private Go modules

    master

    If your project uses private modules, you must configure authentication in your GitHub Action workflow using the following environment variables:

    • GOPRIVATE: A comma-separated list of module path prefixes to be treated as private (e.g., github.com/your-org/*).
    • GITHUB_AUTHENTICATION_TOKEN: A GitHub token with read access to your private repositories.
    name: Run Gosec
    on:
      push:
        branches:
          - master
      pull_request:
        branches:
          - master
    jobs:
      tests:
        runs-on: ubuntu-latest
        env:
          GO111MODULE: on
          GOPRIVATE: github.com/your-org/*
          GITHUB_AUTHENTICATION_TOKEN: ${{ secrets.PRIVATE_REPO_TOKEN }}
        steps:
          - name: Checkout Source
            uses: actions/checkout@v3
          - name: Run Gosec Security Scanner
            uses: securego/gosec@v2
            with:
              args: ./...
  3. Add an AST rule

    master

    AST rules (gosec.Rule) are used for node-level checks. To add one:

    1. Create a new file in rules/ (e.g., rules/unsafe.go).
    2. Implement the rule constructor and Match logic.
    3. Register the rule in rules/rulelist.go.
    4. Add rule-to-CWE mapping in issue/issue.go (and cwe/data.go if new CWE data is required).
    5. Add tests and samples in testutils/ and rule tests in rules/ or analyzer_test.go.
  4. Add an SSA analyzer

    master

    SSA analyzers (analysis.Analyzer) provide whole-program context. To add one:

    1. Create a new file in analyzers/.
    2. Define the analyzer and include buildssa.Analyzer in the Requires field.
    3. Use ssautil.GetSSAResult(pass) to read SSA input.
    4. Return findings as []*issue.Issue.
    5. Register the analyzer in analyzers/analyzerslist.go.
    6. Add rule-to-CWE mapping in issue/issue.go.
    7. Add tests and sample code in analyzers/ and testutils/.
    package analyzers
    
    import (
    	"fmt"
    
    	"golang.org/x/tools/go/analysis"
    	"golang.org/x/tools/go/analysis/passes/buildssa"
    
    	"github.com/securego/gosec/v2/internal/ssautil"
    	"github.com/securego/gosec/v2/issue"
    )
    
    func newMyAnalyzer(id, description string) *analysis.Analyzer {
    	return &analysis.Analyzer{
    		Name:     id,
    		Doc:      description,
    		Run:      runMyAnalyzer,
    		Requires: []*analysis.Analyzer{buildssa.Analyzer},
    	}
    }
    
    func runMyAnalyzer(pass *analysis.Pass) (interface{}, error) {
    	ssaResult, err := ssautil.GetSSAResult(pass)
    	if err != nil {
    		return nil, fmt.Errorf("getting SSA result: %w", err)
    	}
    	_ = ssaResult
    
    	var issues []*issue.Issue
    	return issues, nil
    }
  5. Run gosec as a GitHub Action

    master

    You can run gosec in your GitHub workflows using the securego/gosec@master action. Use the @master tag to pin to the latest stable release for stable behavior.

    name: Run Gosec
    on:
      push:
        branches:
          - master
      pull_request:
        branches:
          - master
    jobs:
      tests:
        runs-on: ubuntu-latest
        env:
          GO111MODULE: on
        steps:
          - name: Checkout Source
            uses: actions/checkout@v3
          - name: Run Gosec Security Scanner
            uses: securego/gosec@master
            with:
              args: ./...
  6. Build and run gosec via Docker

    master
    You can build the gosec Docker image locally or run the existing image against a local project directory. When running via Docker, you must set the working directory (-w) to the project root inside the container so that module dependencies resolve correctly.
  7. Generate TLS rule data

    master

    TLS rule data is derived from Mozilla recommendations. To update the rules/tls_config.go file, run the generator from the repository root.

    If the go generate ./... command fails with exec: "tlsconfig": executable file not found in $PATH, you must install the tlsconfig tool and ensure your GOPATH/bin is in your PATH.

    # Standard generation
    go generate ./...
    
    # If tlsconfig is missing, install it and update PATH
    export PATH="$(go env GOPATH)/bin:$PATH"
    go install ./cmd/tlsconfig
    go generate ./...
  8. Annotate code to suppress false positives

    master

    To suppress specific security findings, use inline comments. The comment must be placed on the line where the warning is reported.

    Supported Formats:

    1. #nosec [RuleList] [-- Justification]
    2. //gosec:disable [RuleList] [-- Justification]

    Example: // #nosec G402 -- Insecure TLS config is required for this internal tool

    Strict Mode: If you want to enforce that all suppressions include rule IDs and justifications, use the following flags:

    • -nosec-require-rules: Rejects naked #nosec / //gosec:disable without rule IDs.
    • -nosec-require-justification: Rejects directives without a -- justification.
    func main() {
    	tr := &http.Transport{
    		TLSClientConfig: &tls.Config{
    			InsecureSkipVerify: true, // #nosec G402
    		},
    	}
    
    	client := &http.Client{Transport: tr}
    	_, err := client.Get("https://go.dev/")
    	if err != nil {
    		fmt.Println(err)
    	}
    }
  9. Understand G118 context propagation failure detection

    master

    The G118 rule uses SSA-level analysis to detect three types of context-related resource leaks or safety issues:

    1. Lost cancel function (CWE-400): Detects when a context.WithCancel, context.WithTimeout, or context.WithDeadline returns a cancel function that is never called.
    2. Goroutine uses context.Background/TODO when request context is available (CWE-400): Detects when a goroutine spawned inside an HTTP handler or a function accepting a context.Context / *http.Request uses context.Background() or context.TODO() instead of the request-scoped context.
    3. Long-running loop without ctx.Done() guard (CWE-400): Detects infinite loops performing blocking I/O (e.g., http.Get, db.Query, time.Sleep) that never check ctx.Done(), making them impossible to cancel.
  10. Quick start with gosec CLI

    master

    Common commands for scanning Go projects and generating reports:

    # Scan all packages in current module
    gosec ./...
    
    # Write JSON report
    gosec -fmt json -out results.json ./...
    
    # Write SARIF report for code scanning
    gosec -fmt sarif -out results.sarif ./...