diff --git a/src/pages/explanations/_meta.ts b/src/pages/explanations/_meta.ts index bd71b03..7ca1092 100644 --- a/src/pages/explanations/_meta.ts +++ b/src/pages/explanations/_meta.ts @@ -17,6 +17,7 @@ export default { 'personal-access-token': { title: 'Personal Access Tokens' }, 'sbom-problem-statement': { title: 'SBOM Problem Statement' }, 'explaining-sboms': { title: 'Explaining SBOMs' }, + 'transitive-dependencies': { title: 'Transitive Dependencies' }, security: { title: 'Security' }, integrations: { title: 'Integrations' }, 'advanced-topics': { title: 'Advanced Topics' }, diff --git a/src/pages/explanations/transitive-dependencies.mdx b/src/pages/explanations/transitive-dependencies.mdx new file mode 100644 index 0000000..8932e37 --- /dev/null +++ b/src/pages/explanations/transitive-dependencies.mdx @@ -0,0 +1,138 @@ +--- +title: Transitive Dependency Risks and Vulnerabilities Explained +description: "What is a transitive dependency? Learn how a transitive dependency introduces hidden vulnerabilities and how DevGuard surfaces them per node." +seo: + robots: index,follow + og: + image: /og-image.png + type: article + schema: + type: TechArticle + keyword_primary: transitive dependency +lang: en-US +ignoreChecks: null +--- + +import { Callout } from '@document-writing-tools/kernux-theme' + +# What Is a Transitive Dependency — and Why It Creates Hidden Vulnerabilities + +Modern software rarely builds on just the packages you explicitly install. Behind every direct dependency lies a tree of further packages — and vulnerabilities anywhere in that tree can put your application at risk. Understanding transitive dependencies is the first step to controlling that risk. + +--- + +## What is a transitive dependency? + +When your application declares a dependency on a package, that package may itself depend on other packages. Those indirect packages are called **transitive dependencies** (also known as indirect dependencies). + +**Example:** + +``` +Your App +└── openssl ← direct dependency + └── libcrypto ← transitive dependency (depth 2) + └── zlib ← transitive dependency (depth 3) +``` + +You declared a dependency on `openssl`. You did not explicitly choose `libcrypto` or `zlib` — but they are pulled into your build and run as part of your application. + +The deeper the dependency tree, the less visibility teams typically have into what is actually running in their software. + +--- + +## What is a transitive vulnerability? + +A **transitive vulnerability** is a security flaw in a transitive dependency that can affect your application, even though the vulnerable package is not one you directly depend on. + +**Concrete example:** + +Your application uses `openssl`. `openssl` depends on `libcrypto`. A CVE is published against `libcrypto`. Even though you never listed `libcrypto` in your dependency file, your application is affected — because `openssl` ships `libcrypto` as part of its own dependency chain. + + + Transitive vulnerabilities are often overlooked in manual reviews because they do not appear in top-level dependency files like `package.json`, `go.mod`, or `requirements.txt`. A full software composition analysis (SCA) scan is required to surface them. + + +--- + +## Why transitive dependencies are a significant risk + +### They are invisible by default + +Most developers only see the packages they directly install. The full dependency tree — which can contain hundreds or thousands of packages in a typical application — is hidden unless you actively inspect it. + +### They are harder to remediate + +Fixing a direct dependency is straightforward: update the version in your manifest. Fixing a transitive vulnerability often requires the maintainer of your direct dependency to release an update first. Until then, you must find workarounds or accept the risk. + +### They account for the majority of vulnerable packages + +In practice, the vast majority of vulnerable packages found in a typical application are transitive — not direct — dependencies. Ignoring them leaves most of your attack surface unaddressed. + +### Triage is harder for transitive vulnerabilities + +When a vulnerability appears in one of your direct dependencies, you can read its code and understand exactly how your application calls it. With a transitive dependency, that visibility is gone: you only know that *some* intermediate package depends on it — you do not know which functions it calls, under what conditions, or whether the vulnerable code path is ever exercised at all. + +This makes it genuinely difficult to answer the question every security team needs to answer: *Is my application actually affected?* + +Research on npm packages confirms this. A [call-graph analysis study on transitive vulnerabilities](https://devguard.org/research-development/vexing-npm-Callgraph-Analyse%20f%C3%BCr%20die%20Reduzierung%20von%20False-positives-bei-der-schwachstellenidentifikation-in-javascript.pdf) found that a vulnerability propagates across a package boundary with roughly **26.3 % probability**. Across two hops the probability drops to about **6.9 %** — following a conditional probability model where each additional hop multiplies the chance of actual exposure: + +``` +P(A affected | C vulnerable) = P(A | B) · P(B | C) = 0.263 · 0.263 ≈ 0.069 +``` + +In absolute numbers the study observed 2,360 directly affected packages — after one inheritance step 1,487 remained (63 %), after two steps only 512. The pattern is consistent exponential decay. + +The practical implication: deeper transitive vulnerabilities are statistically *less likely* to affect your application, but they are also the hardest to verify manually. Tooling that surfaces the full dependency path — and lets you reason per node — is therefore more valuable the deeper the chain goes. + +--- + +## Depth in the dependency graph + +**Depth** describes how many hops a dependency is away from your application: + +| Depth | Description | Example | +|-------|-------------|---------| +| 1 | Direct dependency — you declared it | `openssl` in your `go.mod` | +| 2 | Your direct dependency depends on it | `libcrypto` pulled in by `openssl` | +| 3+ | Further indirect dependencies | `zlib` pulled in by `libcrypto` | + +Greater depth generally correlates with lower probability of actual impact — but does not eliminate risk. A critical vulnerability in a depth-5 package is just as exploitable as one in a direct dependency if your application exercises the code path that reaches it. Depth is a useful signal for prioritisation, not a reason to ignore a finding. + +--- + +## How DevGuard handles transitive dependencies + +When you connect a repository to DevGuard and run a scan, DevGuard performs a full **Software Composition Analysis (SCA)** that resolves the complete dependency graph — not just your top-level packages. + +### The Dependency Risks table + +After a scan, the **Dependency Risks** table in DevGuard shows every vulnerability found across your entire dependency tree. For each finding, DevGuard displays: + +- **The vulnerable package** — the exact component that contains the CVE +- **The dependency path** — the full chain from your application down to the vulnerable package, node by node. DevGuard supports [path pattern matching](/explanations/vulnerability-management/mitigation-strategies#path-pattern-matching) so you can write VEX rules that target specific chains rather than blanket-dismissing a CVE. +- **The depth** — how many hops the vulnerable package is away from your code +- **Severity and exploitability data** — aggregated from NVD, EPSS, OSV, and other sources + +This means you can see not only *that* a vulnerability exists, but *how* your application reaches it — which packages form the chain, and at which node the vulnerable code lives. For a deeper look at how DevGuard resolves these chains, see [Transitive Vulnerability Path Analysis](/explanations/supply-chain-security/transitive-vulnerability-path-analysis). + +### Per-node remediation + +DevGuard lets you act on each node in the dependency path individually. For every transitive vulnerability, you can: + +- **Accept the risk** on a specific node — record that you have assessed the vulnerability in its context and consider it acceptable, with a reason and expiry date +- **Mark as false positive** — if the vulnerable code path is not reachable from your application. See [False Positive Detection](/explanations/vulnerability-management/false-positive-detection) for how DevGuard helps identify these cases. +- **Track remediation** — open an issue directly from the finding and follow the fix through to completion + +This granularity matters because the right action often depends on *where* in the chain the vulnerability lives. A depth-3 vulnerability in a package used only in test code requires a different response than the same CVE in a package invoked on every request. + + + DevGuard generates the dependency graph from the SBOM produced during the scan. The SBOM captures the full component inventory including transitive packages, their versions, and their relationships — giving DevGuard the data it needs to build the complete path from your application to each vulnerability. + + +--- + +## Related + +- [Explaining SBOMs](/explanations/explaining-sboms) — what an SBOM is and why it is the foundation for transitive dependency analysis +- [Vulnerability Management](/explanations/vulnerability-management) — how to prioritize and remediate vulnerabilities found in your dependency tree +- [Run your first scan](/getting-started) — connect your repository and surface transitive vulnerabilities in minutes