Skip to content

feat(parsers): add composer audit, pnpm audit, dotnet vulnerable packages and mix_audit parsers - #15475

Merged
devGregA merged 1 commit into
DefectDojo:devfrom
devGregA:feat/parsers-pkg-advisories
Aug 2, 2026
Merged

feat(parsers): add composer audit, pnpm audit, dotnet vulnerable packages and mix_audit parsers#15475
devGregA merged 1 commit into
DefectDojo:devfrom
devGregA:feat/parsers-pkg-advisories

Conversation

@devGregA

@devGregA devGregA commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Description

Four package-manager advisory parsers, mirroring the existing npm_audit / yarn_audit /
cargo_audit shape: a vendor advisory becomes one finding carrying the advisory's own severity, the
affected package as the component, the fixed version as the mitigation, and the advisory URL as the
reference.

Tool Scan type Output format Severity source
composer audit (PHP) Composer Audit Scan JSON (--format=json --locked) Packagist advisory severity
pnpm audit (Node) pnpm Audit Scan JSON (npm v6 advisories envelope) npm advisory severity
dotnet list package Dotnet Vulnerable Packages Scan JSON (--format json) NuGet advisory severity
mix deps.audit (Elixir) Mix Audit Scan JSON (--format json) Elixir advisory severity

Severities are the tool's own and span Critical→Low across the fixtures. Nothing is imported at a
level the parser picked, and there are no Info findings.

Fixtures — real output, each from a deliberately vulnerable set of pins committed as the sample
input. Tool version and exact command are in each docs page.

Tool Version no / one / many findings
composer audit 2.10.2 0 / 1 / 16
pnpm audit 11.18.0 0 / 2 / 43
dotnet list package .NET SDK 8.0.423 0 / 1 / 4 (2 direct + 2 transitive)
mix deps.audit Elixir 1.17.3, mix_audit 2.1 0 / 1 / 2

Per-tool details worth a reviewer's attention, each covered by a test:

  • composer never reports the installed version — only the affected range — so
    component_version is deliberately left unset rather than filled with a range. Its advisories carry
    both a CVE and a GHSA; both are attached, and the GHSA is the fallback because cve is frequently
    null.
  • pnpm emits the npm v6 envelope, so it is closer to npm_audit than npm_audit_7_plus. It
    has no CVE field at all, so only the GHSA is attached — no CVE is inferred. Its "CWE-1321" string
    is converted to the numeric CWE.
  • dotnet reports no advisory id, only advisoryurl, so the GHSA is parsed out of the URL. Both
    topLevelPackages and transitivePackages are walked — a vulnerable package is usually pulled
    in indirectly and only the transitive list names it. Transitive findings get a mitigation naming the
    real options instead of telling the reader to upgrade a package that is not in their project file.
  • mix deps.audit prints compiler output before the JSON on the first run in a clean checkout,
    which makes the file unparseable. The docs say to capture a second run, and the parser's error
    message names that as the likely cause.

Reproducing the composer fixture needs one non-obvious step, recorded in its docs page: Composer
2.10 refuses to resolve a package affected by a security advisory, so a project pinning vulnerable
versions will not install until config.policy.advisories.block is set to false.

Test results

49 tests across the four parsers, all passing, each file run with V3_FEATURE_LOCATIONS both on and
off
. ruff check . is clean repo-wide without any change to ruff.toml.

Documentation

A page per parser under docs/content/supported_tools/parsers/file/, each with the exact command,
tool version, severity mapping, and the reproduction caveats above.

Deduplication entries added (the only shared file touched):

HASHCODE_FIELDS_PER_SCANNER
  "Composer Audit Scan":             ["component_name", "vuln_id_from_tool"]
  "pnpm Audit Scan":                 ["component_name", "component_version", "vuln_id_from_tool"]
  "Dotnet Vulnerable Packages Scan": ["component_name", "component_version", "vuln_id_from_tool"]
  "Mix Audit Scan":                  ["component_name", "component_version", "vuln_id_from_tool"]

DEDUPLICATION_ALGORITHM_PER_PARSER
  all four -> DEDUPE_ALGO_HASH_CODE

Composer omits component_version for the reason above. description is excluded everywhere: it
carries the advisory prose, which would rehash if a vendor reworded it.

Nothing dropped. All four tools produce real severities, so none hit the "Info-only, drop it"
condition. Verified absent from current dev (253 tool dirs) before building.

Checklist

  • Rebased on latest dev.
  • Submitted against dev — feature, not bugfix.
  • Ruff compliant, ruff.toml unmodified.
  • Python 3.13 compliant — standard library only, no new dependencies.
  • Documentation included for all four.
  • No model changes, so no migrations.
  • Unit tests added (49).

composer audit (PHP), pnpm audit (Node), dotnet list package --vulnerable
(NuGet) and mix deps.audit (Elixir). Each mirrors the existing npm_audit /
yarn_audit / cargo_audit shape: a vendor advisory becomes one finding with the
advisory's own severity, the affected package as the component, the fixed
version as the mitigation and the advisory URL as the reference.

Every severity comes from the tool, spanning Critical to Low across the
fixtures - no finding is imported at a level the parser chose.

Details worth knowing, each covered by a test:

- composer never reports the INSTALLED version, only the affected range, so
  component_version is deliberately left unset instead of being filled with a
  range. Its advisories carry a CVE and a GHSA; both are attached, and the GHSA
  is the fallback because "cve" is frequently null.
- pnpm emits the npm v6 "advisories" envelope, not the npm 7+ shape, and has no
  CVE field at all - the GHSA is the only identifier, and none is inferred. Its
  "CWE-1321" string is converted to the numeric CWE.
- dotnet reports no advisory id, only advisoryurl, so the GHSA is parsed out of
  it. Both topLevelPackages and transitivePackages are walked, because a
  vulnerable package is usually pulled in indirectly and only the transitive
  list names it; transitive findings get a mitigation that names the real
  options rather than telling the reader to upgrade a package that is not in
  their project file.
- mix deps.audit prints compiler output before the JSON on the first run in a
  clean checkout, which makes the file unparseable. The docs say to capture a
  second run and the parser's error message names it.

Fixtures are real output from Composer 2.10.2, pnpm 11.18.0, .NET SDK 8.0.423
and Elixir 1.17.3, each run against deliberately vulnerable pins. 49 tests,
passing with V3_FEATURE_LOCATIONS both on and off.

Only the four parser directories and the two dedupe dicts in settings.dist.py
are touched.
@github-actions github-actions Bot added settings_changes Needs changes to settings.py based on changes in settings.dist.py included in this PR docs unittests parser labels Aug 2, 2026
@devGregA
devGregA merged commit 7863728 into DefectDojo:dev Aug 2, 2026
149 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Import Scans parser settings_changes Needs changes to settings.py based on changes in settings.dist.py included in this PR unittests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants