OWASP / OWASP/cve-lite-cli

fix(PD002): false positives on workspace roots — member-declared dependencies reported as transitive-only phantoms

Open
#966 5 comments 1 reaction 1 assignee View on GitHub

@alamb-hex is already working on this.

Since Aug 11, 2026.

bug
Dominant language
TypeScript
Stars
715
Forks
145
Avg merge
21h 39m
Merged PRs (30d)
66

Description

Summary

When scanning a monorepo root, PD002 reports dependencies that are declared directly in a workspace member's package.json as transitive-only phantoms. Declaration appears to be resolved against the root manifest only, while imports are collected from the whole tree — so every workspace-member dependency that is imported in that member's source is flagged.

Version: 1.28.0 · Package manager: pnpm (workspace via pnpm-workspace.yaml)

Minimal reproduction

repro/
├── package.json            { "name": "pd002-repro", "private": true, "version": "1.0.0" }
├── pnpm-workspace.yaml     packages: ["apps/*"]
└── apps/web/
    ├── package.json        { "name": "@repro/web", "dependencies": { "js-yaml": "^4.1.0" } }
    └── src/index.ts        import yaml from 'js-yaml';
pnpm install
cve-lite . overrides --json
Actual
PD002  medium  js-yaml
  js-yaml is imported in source but only present as a transitive dependency - declare it explicitly
  details: Imported in: apps/web/src/index.ts. If the parent package drops or changes this
           dependency, your code will break without warning. Run: pnpm add js-yaml
Expected

No finding. js-yaml is a declared direct dependency of @repro/web, which is the package that imports it.

The suggested remediation (pnpm add js-yaml) would add a redundant second declaration at the root.

The detail line points at the fix

The finding already reports Imported in: apps/web/src/index.ts. So the import's owning workspace is known at the point the finding is produced — it just isn't used to pick which manifest to resolve the declaration against. Resolving against the nearest enclosing workspace member's package.json (falling back to the root) should close this.

Corroborating: scanning the member directly is clean.

cve-lite ./apps/web overrides --json   # 0 findings
cve-lite .            overrides --json # 1 PD002 finding

Real-world impact

On a real 2-app pnpm monorepo (root manifest declares one devDependency; apps/web declares the rest), a root scan produces 11 PD002 findings, all false — next, react, vitest, tailwindcss, @tanstack/react-query, lucide-react, clsx, tailwind-merge, @testing-library/react, @testing-library/jest-dom, @vitejs/plugin-react.

For a dashboard aggregating findings across many repos, that one project dominates the view with noise, which is what led us to filter PD001/PD002 out of our integration entirely rather than lose the signal from the OA rules.

Notes

  • The scan notes already say "Monorepo workspace boundaries are only partially modeled in this version" — this is a concrete instance.
  • I verified PD002 only. PD001 (override-only phantom) plausibly shares the same declaration-resolution path, but I have not confirmed it.
  • Possibly related in spirit: #943, #947, #949 corrected workspace attribution for dev/prod classification. The PD rules may need the equivalent treatment.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.