Skip to content

Upload govulncheck Results to GitHub Code Scanning for Go

If you already use GitHub security features for Go, it is tempting to assume CodeQL and Dependabot cover everything you need. They do not fully replace govulncheck.

For Go projects, govulncheck adds a very useful layer: it understands the Go vulnerability database and uses package and call graph information to reduce noise. That means it can help answer a more practical question than "is this module version mentioned in an advisory?" It can help answer "does this vulnerability affect code my project actually uses?"

That is enough of a difference that I think govulncheck is worth surfacing directly in GitHub code scanning, not just running as an isolated terminal command or a one-off CI step.

These tools solve different problems:

  • CodeQL finds code-level vulnerabilities and insecure patterns through static analysis.
  • Dependabot alerts find known vulnerable dependencies from manifests and lockfiles.
  • govulncheck finds known Go vulnerabilities and uses Go-specific reachability context to cut down false positives.

That distinction matters because a Go repository can be "green" in one layer and still benefit from another.

CodeQL is not a substitute for govulncheck, and govulncheck is not a substitute for CodeQL. They are complementary signals.

Why Upload SARIF Instead of Just Failing a Job

If you only run govulncheck as a plain workflow step, the results live in job logs. That is better than nothing, but it is not where most maintainers naturally review security findings.

GitHub code scanning is the better home because it gives you:

  • a dedicated alert view
  • alert history over time
  • filtering and triage in the GitHub UI
  • one place to review CodeQL and third-party analysis results together

GitHub supports this model directly through SARIF uploads. CodeQL uploads its own SARIF automatically, but third-party tools need an explicit upload step.

For the GitHub documentation behind that workflow, see:

A Minimal Workflow

The main pieces are:

  1. Check out the repository.
  2. Run govulncheck with SARIF output enabled.
  3. Upload the SARIF file with github/codeql-action/upload-sarif.

One detail worth calling out: add an explicit checkout step. If you use go-package: ./..., the action needs the repository contents available.

I also think push to main plus a scheduled run is a reasonable default here. That catches new changes as they land and rechecks the repository as the vulnerability database evolves. You can add pull_request too, but I would treat that as an intentional tradeoff between earlier feedback and more frequent security workflow noise.

.github/workflows/govulncheck.yml
---
name: Check for Vulnerabilities

on:
  push:
    branches:
      - main
  schedule:
    - cron: "0 0 * * 1"

permissions:
  contents: read
  security-events: write

jobs:
  check-for-vulnerabilities:
    name: Check for Vulnerabilities
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Run govulncheck
        uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4
        with:
          go-package: ./...
          output-format: sarif
          output-file: govulncheck.sarif

      - name: Upload SARIF File
        uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
        with:
          sarif_file: govulncheck.sarif
          category: govulncheck

Why the category Value Helps

The category: govulncheck setting is small, but useful.

It distinguishes these results from CodeQL or any other SARIF-producing tool you may already be uploading. In practice, that makes the code scanning view easier to interpret when multiple tools feed the same alert surface.

If you are already running CodeQL, this is the clean way to say, "these findings came from govulncheck, not from the CodeQL query pack."

What I Would Not Add

You may see examples that print the code scanning results URL into the job log. I would skip that unless you personally find it useful. Once the SARIF upload succeeds, the results are already going to the code scanning interface, and the category value is enough to distinguish them there.

When This Pattern Is Worth It

I think this is especially useful when:

  • The repository is a public Go project.
  • Security findings should be visible in the GitHub UI, not buried in CI logs.
  • You already use code scanning and want Go vulnerability results in the same place.
  • Maintainers want a lower-noise signal than raw dependency advisory matching.

For a tiny internal repository with very little operational overhead, a simple scheduled govulncheck run may be enough. But if the repository already leans on GitHub code scanning, uploading SARIF is the more coherent integration.


If your goal is Go dependency vulnerability visibility in GitHub code scanning, govulncheck is worth adding even if you already run CodeQL and receive Dependabot alerts.

For Go projects, that is a meaningful improvement over treating govulncheck as just another line in a CI log. SARIF upload is what turns that signal into a first-class code scanning result in GitHub.