Safeguard
Developer Tools•

How do I scan a Go repository with several modules and go.work?

Each Go module has its own go.mod, and go.work adds modules to a workspace. Scan every module, and watch how workspace mode can change selected versions.

Safeguard Security Team
3 min read

Scan every module that has its own go.mod, and do not rely on go.work alone. The Go reference says a use directive adds one module directory and does not add modules in subdirectories. Also note that workspace mode can select different versions from the ones a single module build would use.

What go.work does

The Go modules reference describes go.work as a file that adds modules on disk to the set of main modules in a workspace. Each use directive names a relative path to a directory containing a go.mod. A use directive does not add modules that live in subdirectories of its argument, so nested modules need their own entries.

The go command maintains a go.work.sum file for hashes used by the workspace that are not in the modules' go.sum files.

go 1.23.0

use ./services/api
use ./services/worker
use ./libs/shared

Finding every module

Do not assume the use list is complete. List the go.mod files directly:

git ls-files '*go.mod'

Compare that to the use entries. A module with no entry is not part of the workspace build. It may still ship on its own.

SituationWhat it means for scanning
go.mod listed in go.workPart of workspace builds
go.mod not listedBuilt separately, scan it on its own
Nested module under a used folderNeeds its own use entry

Versions can differ between modes

In workspace mode, all workspace modules are main modules, and minimal version selection runs over a graph built from all of them. The highest required version of each dependency across the workspace wins. So a vulnerable version required by one module can be raised by another module's requirement, and the reverse is also possible.

Replace directives in go.work override replace directives in module files. A wildcard replace in go.work overrides a version specific replace in a go.mod file.

The effect is that what you test locally in workspace mode might differ from what each module ships when built alone. Scan each module in its own single module context, using the environment variable that turns workspace mode off, because that matches how an individual service is usually built in CI.

GOWORK=off go list -m all

Should you commit go.work?

The Go reference advises against committing go.work in most cases, noting that a checked in file may cause CI to select and test the wrong versions of a module's dependencies. It names an exception for repositories whose modules are developed only with each other. See should you commit go.work for the decision.

A reliable routine

  1. List all go.mod files.
  2. For each shipped module, resolve with workspace mode off.
  3. Scan the result and the go.sum.
  4. Route findings by module path.

Safeguard scans Go modules and generates SBOMs per project. Try the free scan at https://gold.safeguard.sh/scan.

Quick check

Does a use directive include nested modules?

No. Nested modules need their own use directives.

How do I resolve a module without workspace mode?

Set the GOWORK environment variable to off, which puts the command in a single module context.

Sources

Last reviewed: 19 October 2026.

Never miss an update

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

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.