Safeguard
Supply Chain•

Why do statically linked binaries ignore your apt upgrades?

A statically linked program carries its own copy of libraries, so OS patches never reach it. Rebuild and scan the binary, as with Go and govulncheck.

Safeguard Security Team
4 min read

A statically linked program copies the library code it needs into the executable at build time. Updating the system's shared libraries does not change that copy. To pick up a fix you must rebuild the program with the fixed library or toolchain, and scan the binary itself to find out what it contains.

Dynamic and static in one table

PropertyDynamically linkedStatically linked
Library codeLoaded from shared files on the host at startCopied into the executable
Fixed byUpdating the OS package, then restartingRebuilding the program
Visible to a package database scanThe library appears as a packageThe code does not appear as a package
Common inMost distro packagesMany Go and Rust programs, and minimal container images

If your application image is built from scratch or a very small base, the OS package list can look almost empty while the binary still contains vulnerable code. An empty package list is not a clean bill of health.

Why this surprises teams

The patch habit on Linux is to update packages, then restart services, as in how to find services that need a restart after a library update. That works for shared libraries. It cannot work for code baked into the executable. The package manager has no record of it, and a restart just loads the same old binary.

A worked example with Go

Go programs are usually built as single static executables. The Go vulnerability documentation says govulncheck analyses your code and surfaces vulnerabilities that actually affect you, based on which functions your code calls. Its package documentation adds that it can scan a compiled binary when you pass the path with the binary mode flag. It reads the binary's symbol information, reports vulnerable functions in the main module and dependencies, and omits call stacks, since those need source analysis. If symbol information cannot be extracted, it reports vulnerabilities for all modules the binary depends on. For binaries built with Go versions before 1.18, it reports only standard library vulnerabilities.

govulncheck -mode binary ./myservice

Note the practical lesson: the standard library and toolchain version used at build time matter. A fix in the language's standard library reaches you only after you rebuild with a patched toolchain.

What to do about it

  1. Keep an inventory of which services are static binaries and which are dynamic.
  2. Record the toolchain version in the build, so you can answer "which services were built with the vulnerable version?"
  3. Scan the binary or the built image, not just the OS package list. An SBOM that includes language level components helps, as shown in how to generate an SBOM for a container image.
  4. Rebuild on a schedule and on advisories, with the same discipline you apply to base images.

Try it yourself

Click through the inventory and look for components that come from the application layer rather than OS packages.

Click through it at your own pace, or open it full screen.

Quick check

Will apt upgrade fix a vulnerable library inside a static binary?

No. The code is inside the executable, so only a rebuild with the fixed library or toolchain changes it.

Can I scan a compiled Go program?

Yes. The govulncheck documentation describes a binary mode that takes the path to the executable.

Safeguard's dependency scanning and reachability analysis work at the application layer, which is where this class of finding sits. Run a free scan at gold.safeguard.sh/scan.

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.