Safeguard
Supply Chain•

Reachability and transitive dependencies: tracing the long path

Most vulnerable packages arrive indirectly. See how reachability follows a chain of dependencies, why it helps, and when the chain hides the answer.

Safeguard Security Team
3 min read

A transitive dependency is a package you did not choose, pulled in by one you did. Reachability analysis follows calls across those hops: from your code into a direct dependency, then into the indirect one holding the flaw. If any hop is never called, the path breaks and the finding drops in priority.

Why indirect packages dominate findings

You list perhaps a few dozen direct dependencies. Each brings its own. The lockfile can hold hundreds of packages, and an advisory against any one of them produces a finding in your report. You may not recognize the package name at all.

Version matching treats all of them the same. Direct or indirect, present is present.

How the path works

Take a chain. Your service uses a web client library. The client library uses a parsing library. The parsing library has an advisory.

your code
  client.Fetch
    client.decodeBody
      parser.Read   (advisory here)

If your code calls Fetch, and Fetch calls decodeBody, and decodeBody calls the flawed Read, the path is complete. If your code only uses the client's configuration helpers, the call into the parser never happens, and the finding is not reachable from your code.

What makes transitive cases tricky

  • Library internals change by version. An upgrade can add an internal call to the vulnerable function.
  • Optional features. A client might only use the parser if you set a certain option.
  • Version resolution. Two copies of a package can exist at different versions. Check which one the build uses.
  • Vendored or bundled copies. A copy inside another package may not appear in the lockfile at all, so a scanner using the lockfile will not see it.

Fixing an indirect finding

You cannot edit the library, but you have options.

  1. Upgrade the direct dependency to a release that pulls in a fixed version.
  2. Use your package manager's override or resolution feature to pin a fixed version of the indirect one, then test.
  3. Replace the direct dependency if it is unmaintained.
  4. If the path is not reachable, record the reason and set a review date.

Overrides can break compatibility, so run your tests after any change.

A habit that pays off

When you add a direct dependency, look at what it brings in. A package that drags in a large tree for one small feature is a future noise source. Removing unused direct dependencies removes all of their descendants too. See remove unused dependencies before scanning them.

A realistic example

A build lists three copies of one utility package at different versions, brought in by three direct dependencies. An advisory affects the oldest. Only one direct dependency uses the old copy, and it calls a different function. The finding is real by version, yet the exposure is limited to one part of the app. Reading the lockfile tree to see who brings in which copy took ten minutes and settled the question.

Quick check

Can a transitive vulnerability be reachable?

Yes. Calls can pass through your direct dependency into the indirect one. That is the case reachability analysis traces.

Do I own the risk for packages I did not choose?

Yes. They run in your application, so their flaws are your exposure.

Safeguard's SBOM and dependency scanning cover direct and indirect packages, and reachability analysis adds the call path. Try the free scan.

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.