Skip to content

Commit 3e0635f

Browse files
committed
fix: skip withdrawn OSV advisories in parse_advisory_data_v3
Withdrawn advisories were being imported by the v2 pipeline because parse_advisory_data_v3 in pipes/osv_v2.py had no withdrawn check. This caused packages like pkg:pypi/py@1.11.0 to appear as affected even though the advisory (e.g. GHSA-w596-4wvx-j9j6) was withdrawn. Add a withdrawn check at the top of parse_advisory_data_v3, consistent with the existing check in parse_advisory_data (v1). This fix covers all 5 pipelines that use parse_advisory_data_v3: github_osv_importer, oss_fuzz, pypa_importer, pysec_importer, ubuntu_osv_importer. Add tests for both withdrawn and non-withdrawn cases in test_osv_v2.py. Fixes #2238 Signed-off-by: shivamshrma09 <shivamsharma27107@gmail.com>
1 parent c8f0a89 commit 3e0635f

File tree

5 files changed

+97
-1
lines changed

5 files changed

+97
-1
lines changed

vulnerabilities/importers/github_osv.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ def advisory_data(self) -> Iterable[AdvisoryData]:
5050
)
5151
with open(file) as f:
5252
raw_data = json.load(f)
53-
yield parse_advisory_data(raw_data, supported_ecosystems, advisory_url)
53+
advisory = parse_advisory_data(raw_data, supported_ecosystems, advisory_url)
54+
if advisory:
55+
yield advisory
5456
finally:
5557
if self.vcs_response:
5658
self.vcs_response.delete()

vulnerabilities/importers/osv.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ def parse_advisory_data(
5454
"""
5555
Return an AdvisoryData build from a ``raw_data`` mapping of OSV advisory and
5656
a ``supported_ecosystem`` string.
57+
Return None if the advisory has been withdrawn.
5758
"""
59+
if raw_data.get("withdrawn"):
60+
logger.info(f"Skipping withdrawn advisory: {raw_data.get('id')!r}")
61+
return None
5862
raw_id = raw_data.get("id") or ""
5963
summary = raw_data.get("summary") or ""
6064
details = raw_data.get("details") or ""

vulnerabilities/pipes/osv_v2.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ def parse_advisory_data_v3(
6565
Return an AdvisoryData build from a ``raw_data`` mapping of OSV advisory and
6666
a ``supported_ecosystem`` string.
6767
"""
68+
if raw_data.get("withdrawn"):
69+
logger.info(f"Skipping withdrawn advisory: {raw_data.get('id')!r}")
70+
return None
6871
advisory_id = raw_data.get("id") or ""
6972
if not advisory_id:
7073
logger.error(f"Missing advisory id in OSV data: {raw_data}")

vulnerabilities/tests/pipes/test_osv_v2.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,51 @@
2323
from vulnerabilities.pipes.osv_v2 import parse_advisory_data_v3
2424
from vulnerabilities.tests import util_tests
2525

26+
27+
def test_parse_advisory_data_v3_withdrawn_returns_none():
28+
raw_data = {
29+
"id": "GHSA-w596-4wvx-j9j6",
30+
"published": "2022-10-16T12:00:23Z",
31+
"withdrawn": "2025-08-01T20:34:11Z",
32+
"aliases": ["CVE-2022-42969"],
33+
"summary": "Withdrawn Advisory: ReDoS in py library",
34+
"affected": [
35+
{
36+
"package": {"ecosystem": "PyPI", "name": "py"},
37+
"ranges": [
38+
{
39+
"type": "ECOSYSTEM",
40+
"events": [{"introduced": "0"}, {"last_affected": "1.11.0"}],
41+
}
42+
],
43+
}
44+
],
45+
}
46+
result = parse_advisory_data_v3(
47+
raw_data,
48+
supported_ecosystems=["pypi"],
49+
advisory_url="https://github.com/github/advisory-database/blob/main/advisories/GHSA-w596-4wvx-j9j6.json",
50+
advisory_text="",
51+
)
52+
assert result is None
53+
54+
55+
def test_parse_advisory_data_v3_not_withdrawn_returns_advisory():
56+
raw_data = {
57+
"id": "GHSA-j3f7-7rmc-6wqj",
58+
"published": "2022-01-10T14:12:00Z",
59+
"aliases": ["CVE-2022-0001"],
60+
"summary": "Some valid advisory",
61+
"affected": [],
62+
}
63+
result = parse_advisory_data_v3(
64+
raw_data,
65+
supported_ecosystems=["pypi"],
66+
advisory_url="https://github.com/github/advisory-database/blob/main/advisories/GHSA-j3f7-7rmc-6wqj.json",
67+
advisory_text="",
68+
)
69+
assert result is not None
70+
2671
TEST_DATA = Path(__file__).parent.parent / "test_data" / "osv_test"
2772

2873

vulnerabilities/tests/test_osv.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from vulnerabilities.importers.osv import get_published_date
2525
from vulnerabilities.importers.osv import get_references
2626
from vulnerabilities.importers.osv import get_severities
27+
from vulnerabilities.importers.osv import parse_advisory_data
2728
from vulnerabilities.severity_systems import SCORING_SYSTEMS
2829

2930

@@ -397,3 +398,44 @@ def test_get_fixed_versions4(self):
397398
)
398399

399400
assert results == [SemverVersion("6.5.4")]
401+
402+
def test_parse_advisory_data_withdrawn_returns_none(self):
403+
raw_data = {
404+
"id": "GHSA-w596-4wvx-j9j6",
405+
"published": "2022-10-16T12:00:23Z",
406+
"withdrawn": "2025-08-01T20:34:11Z",
407+
"aliases": ["CVE-2022-42969"],
408+
"summary": "Withdrawn Advisory: ReDoS in py library",
409+
"affected": [
410+
{
411+
"package": {"ecosystem": "PyPI", "name": "py"},
412+
"ranges": [
413+
{
414+
"type": "ECOSYSTEM",
415+
"events": [{"introduced": "0"}, {"last_affected": "1.11.0"}],
416+
}
417+
],
418+
}
419+
],
420+
}
421+
result = parse_advisory_data(
422+
raw_data,
423+
supported_ecosystems=["pypi"],
424+
advisory_url="https://github.com/github/advisory-database/blob/main/advisories/GHSA-w596-4wvx-j9j6.json",
425+
)
426+
assert result is None
427+
428+
def test_parse_advisory_data_not_withdrawn_returns_advisory(self):
429+
raw_data = {
430+
"id": "GHSA-j3f7-7rmc-6wqj",
431+
"published": "2022-01-10T14:12:00Z",
432+
"aliases": ["CVE-2022-0001"],
433+
"summary": "Some valid advisory",
434+
"affected": [],
435+
}
436+
result = parse_advisory_data(
437+
raw_data,
438+
supported_ecosystems=["pypi"],
439+
advisory_url="https://github.com/github/advisory-database/blob/main/advisories/GHSA-j3f7-7rmc-6wqj.json",
440+
)
441+
assert result is not None

0 commit comments

Comments
 (0)