@@ -100,7 +100,6 @@ def fetch_nuclei_data(cve_id):
100100
101101
102102def fetch_vulncheck_data (cve_id ):
103- config = load_config ()
104103 vulncheck_api_key = config .get ("vulncheck_api_key" )
105104 if not vulncheck_api_key :
106105 return None , "API key for VulnCheck is not configured correctly."
@@ -164,7 +163,8 @@ def template(data):
164163 cve_item = data ["containers" ]["cna" ]
165164 published = data ["cveMetadata" ].get ("datePublished" , "" )
166165 if published :
167- published_date = datetime .datetime .fromisoformat (published .rstrip ("Z" ))
166+ published_date = datetime .datetime .fromisoformat (
167+ published .rstrip ("Z" ))
168168 published = published_date .strftime ("%Y-%m-%d" )
169169 description = (
170170 next (
@@ -209,13 +209,15 @@ def template(data):
209209 epss_score = data ["data" ][0 ].get ("epss" , "N/A" )
210210 return (
211211 [
212- f"└ EPSS Score: { float (epss_score ) * 100 :.2f} % Probability of exploitation."
212+ f"└ EPSS Score: {
213+ float (epss_score ) * 100 :.2f} % Probability of exploitation."
213214 ]
214215 if epss_score != "N/A"
215216 else []
216217 )
217218
218- display_data ("♾️ Exploit Prediction Score (EPSS)" , epss_data , template , error )
219+ display_data ("♾️ Exploit Prediction Score (EPSS)" ,
220+ epss_data , template , error )
219221
220222
221223def display_cisa_status (cve_id , cisa_data , error = None ):
@@ -246,7 +248,8 @@ def template(data):
246248 created_date = datetime .datetime .fromisoformat (created_at )
247249 created_at = created_date .strftime ("%Y-%m-%d" )
248250 entries .append (
249- f"├ Date: { created_at } \n └ URL: { poc .get ('html_url' , 'N/A' )} "
251+ f"├ Date: { created_at } \n └ URL: {
252+ poc .get ('html_url' , 'N/A' )} "
250253 )
251254 if index < len (data .get ("pocs" , [])) - 1 :
252255 entries .append ("|" )
@@ -293,7 +296,8 @@ def template(data):
293296 sorted (data , key = lambda x : x ["date" ], reverse = True )
294297 ):
295298 url = f"https://www.exploit-db.com/exploits/{ item ['id' ]} "
296- entries .append (f"├ Date: { item ['date' ]} \n └ URL: { url } " )
299+ entries .append (f"├ Date: {
300+ item ['date' ]} \n └ URL: { url } " )
297301 if index < len (data ) - 1 :
298302 entries .append ("|" )
299303 return entries if entries else ["└ ❌ No data found." ]
@@ -360,7 +364,8 @@ def calculate_priority(
360364 except (KeyError , IndexError , TypeError ):
361365 pass
362366 in_cisa_kev = (
363- any (vuln ["cveID" ] == cve_id for vuln in cisa_data .get ("vulnerabilities" , []))
367+ any (vuln ["cveID" ] == cve_id for vuln in cisa_data .get (
368+ "vulnerabilities" , []))
364369 if cisa_data
365370 else False
366371 )
@@ -399,10 +404,11 @@ def template(data):
399404 if priority is None :
400405 display_data ("⚠️ Patching Priority Rating" , None , template )
401406 else :
402- display_data ("⚠️ Patching Priority Rating" , {"priority" : priority }, template )
407+ display_data ("⚠️ Patching Priority Rating" , {
408+ "priority" : priority }, template )
403409
404410
405- def load_config ():
411+ def load_config (debug = False ):
406412 default_config = {"vulncheck_api_key" : None , "openai_api_key" : None }
407413 base_path = os .path .dirname (os .path .abspath (__file__ ))
408414 config_paths = [
@@ -415,23 +421,27 @@ def load_config():
415421 for config_path in config_paths :
416422 if os .path .exists (config_path ):
417423 try :
418- with open (config_path , "r" ) as file :
419- return json .load (file )
420- except json .JSONDecodeError :
421- print (
422- f"⚠️ Error decoding JSON from the config file { config_path } , using default settings."
423- )
424+ if debug :
425+ print (f"⚠️ Attempting to load config file from: {
426+ config_path } " )
427+ with open (config_path , "r" , encoding = "utf-8" ) as file :
428+ config = json .load (file )
429+ if debug :
430+ print (f"⚠️ Successfully loaded config file: {
431+ config_path } " )
432+ return config
433+ except json .JSONDecodeError as e :
434+ print (f"⚠️ Error decoding JSON from the config file {
435+ config_path } : { e } " )
424436 except Exception as e :
425- print (
426- f"⚠️ Unexpected error reading config file { config_path } : { e } , using default settings."
427- )
437+ print (f"⚠️ Unexpected error reading config file {
438+ config_path } : { e } " )
428439
429440 print ("⚠️ Config file not found in any checked locations, using default settings." )
430441 return default_config
431442
432443
433444def get_risk_assessment (cve_details , cve_data ):
434- config = load_config ()
435445 api_key = config .get ("openai_api_key" )
436446
437447 if not api_key :
@@ -454,7 +464,7 @@ def get_risk_assessment(cve_details, cve_data):
454464 Provide a detailed risk assessment including the nature of the vulnerability & its business impact. Describe the likelihood and ease of exploitation, and potential impacts on confidentiality, integrity, and availability.
455465
456466 2. Potential Attack Scenarios
457- Describe at least one potential attack scenarios that leverage this vulnerability. Each scenario should include a detailed description of the attack vector, the attack process, and the potential outcomes.
467+ Describe at least one potential attack scenarios that leverage this vulnerability. Each scenario should include a detailed description of the attack vector, the attack process, and the potential outcomes.
458468
459469 3. Mitigation Recommendations
460470 Provide specific, actionable mitigation recommendations. Include immediate actions such as patching. Provide links to relevant resources where applicable.
@@ -592,7 +602,8 @@ def import_file(file_path, parse_function):
592602 except json .JSONDecodeError as e :
593603 print (f"❌ Error parsing the JSON file '{ file_path } ': { e } " )
594604 except Exception as e :
595- print (f"❌ An unexpected error occurred while processing '{ file_path } ': { e } " )
605+ print (f"❌ An unexpected error occurred while processing '{
606+ file_path } ': { e } " )
596607 return []
597608
598609
@@ -602,7 +613,8 @@ def is_valid_cve_id(cve_id):
602613
603614def generate_filename (cve_ids , extension ):
604615 timestamp = datetime .datetime .now ().strftime ("%Y%m%d%H%M%S" )
605- cve_part = "_" .join (cve_ids [:3 ]) + ("_and_more" if len (cve_ids ) > 3 else "" )
616+ cve_part = "_" .join (cve_ids [:3 ]) + \
617+ ("_and_more" if len (cve_ids ) > 3 else "" )
606618 return f"{ timestamp } _{ cve_part } _export.{ extension } "
607619
608620
@@ -625,7 +637,8 @@ def template(data):
625637 env = Environment (loader = FileSystemLoader (path ))
626638 break
627639 else :
628- print ("❌ HTML template 'report_template.html' not found in any checked locations." )
640+ print (
641+ "❌ HTML template 'report_template.html' not found in any checked locations." )
629642 return ["❌ Error exporting to HTML: template not found" ]
630643
631644 env .filters ["datetimeformat" ] = datetimeformat
@@ -640,10 +653,12 @@ def template(data):
640653
641654 def handle_cvss (data ):
642655 for result in data :
643- metrics = result .get ("CVE Data" , {}).get ("containers" , {}).get ("cna" , {}).get ("metrics" , [])
656+ metrics = result .get ("CVE Data" , {}).get (
657+ "containers" , {}).get ("cna" , {}).get ("metrics" , [])
644658 for metric in metrics :
645659 if "cvssV3_1" not in metric and "cvssV3" not in metric :
646- metric ["cvssV3_1" ] = {"baseScore" : "N/A" , "baseSeverity" : "N/A" , "vectorString" : "N/A" }
660+ metric ["cvssV3_1" ] = {
661+ "baseScore" : "N/A" , "baseSeverity" : "N/A" , "vectorString" : "N/A" }
647662 return data
648663
649664 try :
@@ -652,8 +667,6 @@ def handle_cvss(data):
652667 print (f"❌ Error exporting to HTML: { e } " )
653668
654669
655-
656-
657670def export_to_json (all_results , cve_ids ):
658671 def template (data ):
659672 filename = generate_filename (cve_ids , "json" )
@@ -718,7 +731,8 @@ def main(cve_ids, export_format=None, import_file=None, import_type=None):
718731 cve_id = cve_id .upper ()
719732 if not is_valid_cve_id (cve_id ):
720733 print (
721- f"❌ Invalid CVE ID format: { cve_id } . Please use the format CVE-YYYY-NNNNN."
734+ f"❌ Invalid CVE ID format: {
735+ cve_id } . Please use the format CVE-YYYY-NNNNN."
722736 )
723737 continue
724738
@@ -826,7 +840,8 @@ def main(cve_ids, export_format=None, import_file=None, import_type=None):
826840 vulncheck_exploits = (
827841 "\n " .join (
828842 [
829- f"{ xdb ['date_added' ]} : { xdb ['clone_ssh_url' ].replace ('git@github.com:' , 'https://github.com/' ).replace ('.git' , '' )} "
843+ f"{ xdb ['date_added' ]} : { xdb ['clone_ssh_url' ].replace (
844+ 'git@github.com:' , 'https://github.com/' ).replace ('.git' , '' )} "
830845 for item in vulncheck_data .get ("data" , [])
831846 for xdb in item .get ("vulncheck_xdb" , [])
832847 ]
@@ -838,7 +853,8 @@ def main(cve_ids, export_format=None, import_file=None, import_type=None):
838853 packetstorm_url = packetstorm_data .get ("packetstorm_url" , "N/A" )
839854
840855 nuclei_url = (
841- f"https://raw.githubusercontent.com/projectdiscovery/nuclei-templates/main/{ nuclei_data ['file_path' ]} "
856+ f"https://raw.githubusercontent.com/projectdiscovery/nuclei-templates/main/{
857+ nuclei_data ['file_path' ]} "
842858 if nuclei_data and "file_path" in nuclei_data
843859 else "N/A"
844860 )
@@ -894,6 +910,7 @@ def main(cve_ids, export_format=None, import_file=None, import_type=None):
894910 elif export_format == "html" :
895911 export_to_html (all_results , cve_ids )
896912
913+
897914def cli ():
898915 display_banner ()
899916 parser = argparse .ArgumentParser (
@@ -924,10 +941,20 @@ def cli():
924941 type = str ,
925942 help = "Path to an import file from a vulnerability scanner. If used, CVE IDs can be omitted from the command line arguments." ,
926943 )
944+ parser .add_argument (
945+ "-d" ,
946+ "--debug" ,
947+ action = "store_true" ,
948+ help = "Enable debug output."
949+ )
927950
928951 args = parser .parse_args ()
929952
953+ global config
954+ config = load_config (args .debug )
955+
930956 main (args .cve_ids , args .export , args .import_file , args .type )
931957
958+
932959if __name__ == "__main__" :
933960 cli ()
0 commit comments