1111import json
1212import logging
1313from datetime import date
14+ from datetime import timezone
1415from traceback import format_exc as traceback_format_exc
1516from typing import Iterable
1617
@@ -93,7 +94,7 @@ def advisories_count(self):
9394 return advisory_count
9495
9596 def collect_advisories (self ) -> Iterable [AdvisoryData ]:
96- for _year , cve_data in fetch_cve_data_1_1 (logger = self .log ):
97+ for _year , cve_data in fetch_cve_data_2_0 (logger = self .log ):
9798 yield from to_advisories (cve_data = cve_data )
9899
99100
@@ -111,15 +112,15 @@ def fetch(url, logger=None):
111112 return json .loads (data )
112113
113114
114- def fetch_cve_data_1_1 (starting_year = 2025 , logger = None ):
115+ def fetch_cve_data_2_0 (starting_year = 2002 , logger = None ):
115116 """
116117 Yield tuples of (year, lists of CVE mappings) from the NVD, one for each
117118 year since ``starting_year`` defaulting to 2002.
118119 """
119120 current_year = date .today ().year
120121 # NVD json feeds start from 2002.
121122 for year in range (starting_year , current_year + 1 ):
122- download_url = f"https://nvd.nist.gov/feeds/json/cve/1.1 /nvdcve-1.1 -{ year } .json.gz"
123+ download_url = f"https://nvd.nist.gov/feeds/json/cve/2.0 /nvdcve-2.0 -{ year } .json.gz"
123124 yield year , fetch (url = download_url , logger = logger )
124125
125126
@@ -151,7 +152,7 @@ def from_cve_data(cls, cve_data, skip_hardware=True):
151152 """
152153 Yield CVE items mapping from a cve_data list of CVE mappings from the NVD.
153154 """
154- for cve_item in cve_data .get ("CVE_Items " ) or []:
155+ for cve_item in cve_data .get ("vulnerabilities " ) or []:
155156 if not cve_item :
156157 continue
157158 if not isinstance (cve_item , dict ):
@@ -163,7 +164,7 @@ def from_cve_data(cls, cve_data, skip_hardware=True):
163164
164165 @property
165166 def cve_id (self ):
166- return self .cve_item ["cve" ]["CVE_data_meta" ][ "ID " ]
167+ return self .cve_item ["cve" ]["id " ]
167168
168169 @property
169170 def summary (self ):
@@ -175,8 +176,8 @@ def summary(self):
175176 # In the remaining 1% cases this returns the longest summary.
176177 # FIXME: we should retun the full description WITH the summry as the first line instead
177178 summaries = []
178- for desc in get_item (self .cve_item , "cve" , "description" , "description_data " ) or []:
179- if desc .get ("value" ):
179+ for desc in get_item (self .cve_item , "cve" , "descriptions " ) or []:
180+ if desc .get ("value" ) and desc . get ( "lang" ) == "en" :
180181 summaries .append (desc ["value" ])
181182 return max (summaries , key = len ) if summaries else None
182183
@@ -187,11 +188,12 @@ def cpes(self):
187188 """
188189 # FIXME: we completely ignore the configurations here
189190 cpes = []
190- for node in get_item (self .cve_item , "configurations" , "nodes" ) or []:
191- for cpe_data in node .get ("cpe_match" ) or []:
192- cpe23_uri = cpe_data .get ("cpe23Uri" )
193- if cpe23_uri and cpe23_uri not in cpes :
194- cpes .append (cpe23_uri )
191+ for nodes in get_item (self .cve_item , "cve" , "configurations" ) or []:
192+ for node in nodes .get ("nodes" ) or []:
193+ for cpe_data in node .get ("cpeMatch" ) or []:
194+ cpe23_uri = cpe_data .get ("criteria" )
195+ if cpe23_uri and cpe23_uri not in cpes :
196+ cpes .append (cpe23_uri )
195197 return cpes
196198
197199 @property
@@ -250,7 +252,7 @@ def reference_urls(self):
250252 # FIXME: we should also collect additional data from the references such as tags and ids
251253
252254 urls = []
253- for reference in get_item (self .cve_item , "cve" , "references" , "reference_data" ) or []:
255+ for reference in get_item (self .cve_item , "cve" , "references" ) or []:
254256 ref_url = reference .get ("url" )
255257 if ref_url and ref_url .startswith (("http" , "ftp" )) and ref_url not in urls :
256258 urls .append (ref_url )
@@ -300,9 +302,7 @@ def weaknesses(self):
300302 Return a list of CWE IDs like: [119, 189]
301303 """
302304 weaknesses = []
303- for weaknesses_item in (
304- get_item (self .cve_item , "cve" , "problemtype" , "problemtype_data" ) or []
305- ):
305+ for weaknesses_item in get_item (self .cve_item , "cve" , "weaknesses" ) or []:
306306 weaknesses_description = weaknesses_item .get ("description" ) or []
307307 for weaknesses_value in weaknesses_description :
308308 cwe_id = (
@@ -322,7 +322,9 @@ def to_advisory(self):
322322 aliases = [],
323323 summary = self .summary ,
324324 references_v2 = self .references ,
325- date_published = dateparser .parse (self .cve_item .get ("publishedDate" )),
325+ date_published = dateparser .parse (self .cve_item ["cve" ].get ("published" )).replace (
326+ tzinfo = timezone .utc
327+ ),
326328 weaknesses = self .weaknesses ,
327329 severities = self .severities ,
328330 url = f"https://nvd.nist.gov/vuln/detail/{ self .cve_id } " ,
0 commit comments