diff --git a/website/docs/how-remediation-works.mdx b/website/docs/how-remediation-works.mdx index a0dd0915..9dc49534 100644 --- a/website/docs/how-remediation-works.mdx +++ b/website/docs/how-remediation-works.mdx @@ -473,6 +473,66 @@ The same package name appearing twice in your scan output is not a duplicate — --- +## Direct and transitive versions of the same package + +The same package name can appear as both a direct dependency and a transitive dependency when different versions are installed. These are independent installs, and each installed version must be classified independently. + +A version is direct only when that specific installed version matches the dependency declared by the project. Another installed version with the same package name can still be transitive when it arrives through unrelated parent packages. + +For example, a project may declare `uuid@14.0.1` directly, while `nyc@15.1.0` introduces a vulnerable `uuid@8.3.2` transitively through `istanbul-lib-processinfo@2.0.3`: + +```mermaid +flowchart TD + P(["Your project"]) + P --> D["uuid@14.0.1\ndirect dependency"] + P --> N["nyc@15.1.0\nparent package"] + N --> I["istanbul-lib-processinfo@2.0.3\nintermediate package"] + I --> V["uuid@8.3.2\ntransitive and vulnerable"] + + style P fill:#1e3a5f,color:#93c5fd,stroke:#3b82f6,padding:12px + style D fill:#14532d,color:#86efac,stroke:#22c55e,padding:12px + style N fill:#1e293b,color:#cbd5e1,stroke:#475569,padding:12px + style I fill:#1e293b,color:#cbd5e1,stroke:#475569,padding:12px + style V fill:#7f1d1d,color:#fca5a5,stroke:#ef4444,padding:12px +``` + +Running `npm install uuid@9.0.0` targets the direct dependency slot in your `package.json`. It updates your declared direct dependency but leaves the vulnerable transitive `uuid@8.3.2` controlled by the parent package untouched in the lockfile. + +Because the vulnerable `uuid@8.3.2` is controlled by the parent package or dependency path that introduced it, remediation should target that parent instead of the unrelated direct `uuid@14.0.1` dependency. + +If the parent's declared range already allows a non-vulnerable version, refreshing the lockfile may resolve the finding. If it does not, the parent package may need to be upgraded to a version with a compatible, non-vulnerable dependency range. + +In this example, CVE Lite CLI selects `nyc` as the actionable parent upgrade path based on the dependency path it resolves in your lockfile. This upgrade crosses major versions, so review `nyc`'s changelog before applying it and rescan afterward to confirm the finding is resolved. + +**Generated command:** + + + + ```bash + npm install nyc@18.0.0 + ``` + + + ```bash + pnpm add nyc@18.0.0 + ``` + + + ```bash + yarn add nyc@18.0.0 + ``` + + + ```bash + bun add nyc@18.0.0 + ``` + + + +This follows the parent upgrade remediation path described in Case 3 above. The generated command targets the parent package that controls the vulnerable transitive `uuid@8.3.2`, not the unrelated direct `uuid@14.0.1` dependency. + +--- + ## Offline mode When running with `--offline` or `--offline-db`, CVE Lite CLI cannot make registry calls. This affects transitive remediation: