Setup Go Proxy with DevGuard Dependency Proxy

The XZ Utils backdoor discovered in 2024 (CVE-2024-3094) was a stark reminder that supply chain attacks are not limited to dynamic language ecosystems — a malicious contributor spent years gaining trust before inserting a backdoor into a widely deployed compression library. While the Go module proxy protocol provides strong integrity guarantees through checksums, it does not protect against modules that are malicious by design. The DevGuard dependency proxy adds that missing layer, checking every module against the OSV dataset before it is written to your module cache.

  • Registry URL: <your-devguard-url>/api/v1/dependency-proxy/go

Configuration

Set the GOPROXY environment variable to point at DevGuard. Go will use it for all subsequent module downloads in that shell session:

To make this permanent, add it to your CI environment or shell profile. For project-scoped configuration, set it in your CI/CD platform's environment variable configuration alongside your other build variables.

Go only contacts the proxy for modules that are not in your local module cache yet. To see every download go through DevGuard, try it in a fresh module with its own module cache:

Then use go get as usual:

Testing

DevGuard ships a test module that is permanently flagged as malicious for all versions:

If the request is blocked, the proxy is working correctly. Legitimate modules in the same session will resolve normally.

Testing version normalization (semver)

Go module versions must already be canonical vX.Y.Z strings, so equivalent-spelling bypasses (like a leading zero or a missing v) are less of a concern here than for npm or PyPI. Still, DevGuard ships a second test module, github.com/fake-org/malicious-package-versioned, flagged at the specific version v1.0.0 rather than for all versions, so version comparison itself can be verified directly against a resolved version instead of relying on the "any version" fixture above:

Checksum verification keeps working behind the proxy: go looks up the checksums of downloaded modules in the Go checksum database, and DevGuard forwards these requests unchanged.

Testing the minimum package age

The minimum package age is configured per repository and only applies to requests using the repository's proxy URL, which contains a secret. The proxy removes versions that are too new from the version list, so go get resolves to the newest version that is old enough. Downloads of a too new version (.info, .mod, .zip) are rejected.

To verify it, temporarily set the minimum age to 87600 hours (10 years). github.com/pkg/errors@v0.9.1 was published in January 2020, so the proxy must reject it, while go get without a version still resolves to an older version:

Further Reading

Have feedback? We want to hear from you!

Fields marked with * are required