Skip to content

fix(scan): collapse advisory records OSV marks as the same vulnerability - #1320

Open
sonukapoor wants to merge 2 commits into
mainfrom
bugfix/issue-1318-collapse-aliased-advisories
Open

sonukapoor wants to merge 2 commits into
mainfrom
bugfix/issue-1318-collapse-aliased-advisories

Conversation

@sonukapoor

Copy link
Copy Markdown
Collaborator

OSV can serve the same vulnerability as two advisory records that name each other as aliases, and we counted both, so one vulnerability appeared twice inside a finding.

Records are now collapsed only where the aliasing is mutual, so a one-way alias is left alone. The survivor keeps the higher severity, ties break on the smaller id, and the absorbed record's other aliases carry across so nothing leaves the id set.

Mutation testing on the tests found a line in the first draft that nothing could observe, and it is gone rather than left in place with a test written around it.

⚠ Worth knowing before the next accuracy sweep: the sweep must compare against the union of id and aliases rather than reading id alone. A collapsed pair otherwise reads as a disagreement that is not one, which is exactly what happened the first time this ran.

Closes #1318

Two databases can describe one flaw, and OSV records that by having each entry
name the other in aliases. We read OSV faithfully, so both arrive and one
vulnerability is counted twice on the same package. Real cases: two GHSAs for a
lodash prototype pollution, and an EEF and a GHSA record for phoenix, which
crosses two databases.

The test is mutual naming and nothing weaker. OSV aliasing is not always
symmetric, so a one-directional reference can mean related rather than same, and
a shared CVE is weaker still since two advisories may legitimately cite one CVE.

The survivor keeps the higher severity so maxSeverity cannot change, ties break
on the smaller id so output is stable, and the absorbed id is kept in the
survivor's aliases. That last part matters: the accuracy sweep compares our
advisory ids against OSV's, and losing an id reads as a missed advisory rather
than a de-duplicated one.

Measured: Max's tree 52 advisory entries to 51, CopilotKit 333 to 332, findings
and severity distribution identical in both.
…dead

Eight cases. Mutation testing found two problems in the implementation rather
than in the tests, which is what it is for.

Accepting a one-directional alias, keeping the lower severity, and making the
tie-break non-deterministic each fail only the case named for them.

Two mutations survived the first pass. Removing `ids.add(droppedId)` changed
nothing, because mutual naming is the collapse condition, so the survivor already
lists every absorbed id and that line could never add anything. It is gone.

Dropping the malformed-alias filter also changed nothing, because the test only
asserted that it did not throw, and nothing here calls a string method on an
alias. The filter does earn its place for a different reason: the survivor's
aliases is typed string[] and is serialised into the JSON and SARIF payloads, so
a null reaching it would ship. The test now asserts the output is clean, and both
mutations fail against it.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(advisory): mutually aliased OSV records are counted as two vulnerabilities

1 participant