Safeguard
Security Guides•

Imported vs called: what gap does reachability analysis measure?

Importing a vulnerable package is not the same as calling its vulnerable function. Learn the gap reachability measures, with a Go example from its docs.

Safeguard Security Team
3 min read

Importing a package means your build includes it. Calling a function means your program can actually run that code. Reachability analysis measures the gap between the two. A vulnerability in an imported package you never call into is a different risk from one sitting on a path your code uses.

Three levels of "present"

Think of three questions, each narrower than the last.

  1. Is the package in your dependency tree? This is what a basic inventory shows.
  2. Is it imported by code that is built into your program? Some packages sit in the tree but are never compiled in.
  3. Can execution reach the vulnerable function? This is reachability.

Many alerts come from level one. Reachability moves a finding to level three only when a path exists.

What the Go tooling shows

The Go team's govulncheck tutorial gives a clear picture because the tool reports all three states. In the tutorial, the tool prints a call stack when the sample code calls a vulnerable function, for example a line showing the main function calling a function in a language parsing package. For another advisory, the output says there is a vulnerability in a package that the code imports, but the code does not call the affected function, and tells you no action is needed for that one, though it may be worth a look. The tutorial labels such cases as informational.

The command documentation adds that the tool analyses source code or a binary's symbol table to narrow reports, and that results depend on the build configuration, such as the Go version and platform.

This is a language specific example, but the idea carries over. A good report separates "present", "imported", and "called".

Why the gap exists so often

  • Libraries are wide. You use three functions from a package of three hundred.
  • Transitive dependencies are pulled in for features you do not use.
  • Vulnerabilities usually live in one function or parser, not the whole package.

What to do with each level

LevelTypical action
In tree, not importedLow urgency, clean up when convenient
Imported, not calledSchedule fix, note the evidence, recheck on change
CalledPrioritise, check exposure of the entry point

Imported but not called is the tempting category to ignore forever. Do not. Code changes, and a new call can appear in a refactor. Keep the finding open with a lower priority and let a re-run close it when the dependency is updated.

Try it yourself

Click through it at your own pace, or open it full screen. Compare the full list of findings with the list after the reachability filter.

Safeguard includes reachability analysis alongside SBOM and dependency scanning, and you can run a free scan at gold.safeguard.sh/scan to see the output on your own repository.

Quick check

Does an unused import count as risk?

It is lower risk than a called function, but not zero. Some packages run code at import time, and a later change could add a call.

Can a tool see calls made through reflection?

Often not. Reflection decides what to call at runtime, which is a known gap for static analysis.

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.