Skip to content

fix(bundler-audit): reset advisory fields so warnings cannot inherit stale values - #15716

Open
mhuzaifa3 wants to merge 1 commit into
DefectDojo:bugfixfrom
mhuzaifa3:bundler-audit-field-scope
Open

fix(bundler-audit): reset advisory fields so warnings cannot inherit stale values#15716
mhuzaifa3 wants to merge 1 commit into
DefectDojo:bugfixfrom
mhuzaifa3:bundler-audit-field-scope

Conversation

@mhuzaifa3

Copy link
Copy Markdown

Description

BundlerAuditParser.get_findings resets advisory_id at the top of each warning block, but leaves gem_name, gem_version, advisory_title, advisory_url, advisory_solution and sev bound from the previous iteration. Only Name is guaranteed in bundler-audit output, so a warning that omits any other field is rendered against whatever the preceding warning happened to set.

Three failure modes, none caught by the existing fixtures because every warning in them carries a complete field set:

Input Current behaviour
warning with no Advisory/CVE/GHSA line TypeError: can only concatenate str (not "NoneType") to str
incomplete warning with nothing before it UnboundLocalError: cannot access local variable 'advisory_title'
incomplete warning after a complete one silently inherits the previous advisory's values

The third is the damaging one. A sprockets advisory that omits Criticality, Title and Solution takes rack's title, rack's High severity and rack's remediation text, so the finding tells the user to apply rack's fix to sprockets:

title:      Gem sprockets: Directory traversal in Rack::Directory [CVE-2018-3760]
severity:   High
mitigation: upgrade to ~> 2.1.3, >= 2.2.0

Fix

Reset every field per warning, and build the title, description and dedupe fingerprint from the fields actually present, so a warning is a function of its own text.

A missing Criticality line maps to Medium, matching the existing handling of bundler-audit's Unknown criticality. Happy to make that Info instead if you would rather unrated advisories not inflate severity.

Test results

Three fixtures and three tests added, one per failure mode:

  • unittests/scans/bundler_audit/no_advisory_id.txt
  • unittests/scans/bundler_audit/incomplete_first.txt
  • unittests/scans/bundler_audit/partial_fields.txt

With the fix applied:

Ran 5 tests in 0.008s
OK

With the fix reverted and the new tests kept:

Ran 5 tests in 0.009s
FAILED (failures=1, errors=2)

UnboundLocalError: cannot access local variable 'advisory_title'
TypeError: can only concatenate str (not "NoneType") to str
AssertionError: 'Gem sprockets [CVE-2018-3760]' != 'Gem sprockets: Directory traversal in Rack::Directory [33 chars]760]'

Output for well-formed reports is byte-identical, dedupe fingerprint included, so no recorded sample changes and existing findings do not churn on upgrade. Both pre-existing tests pass unmodified. Ruff clean per ruff.toml.

Documentation

No documentation change needed. Behaviour for well-formed reports is unchanged.

…stale values

get_findings resets advisory_id at the top of each warning block but leaves gem_name,
gem_version, advisory_title, advisory_url, advisory_solution and sev bound from the
previous iteration. Only Name is guaranteed in bundler-audit output, so a warning that
omits any other field is rendered against whatever the preceding warning happened to set.

Three consequences, all observable:

  warning with no Advisory/CVE/GHSA line
    TypeError: can only concatenate str (not "NoneType") to str
  incomplete warning with nothing before it
    UnboundLocalError: cannot access local variable 'advisory_title'
  incomplete warning after a complete one
    Gem sprockets: Directory traversal in Rack::Directory [CVE-2018-3760]

The third is the damaging one. A sprockets advisory that omits Criticality, Title and
Solution takes rack's title, rack's High severity and rack's remediation text, so the
finding tells the user to apply rack's fix to sprockets.

Resetting every field per warning, and building the title, description and fingerprint
from the fields actually present, makes a warning a function of its own text. A missing
Criticality line maps to Medium, matching the existing handling of bundler-audit's
"Unknown" criticality.

Identity is not affected: both existing fixtures parse to byte-identical findings, dedupe
fingerprint included, so no recorded sample changes and existing findings do not churn on
upgrade.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant