Skip to content

Instantly share code, notes, and snippets.

@righettod
Last active November 26, 2025 05:46
Show Gist options
  • Select an option

  • Save righettod/770eab8fbe6918db3b2c33baf8873cfa to your computer and use it in GitHub Desktop.

Select an option

Save righettod/770eab8fbe6918db3b2c33baf8873cfa to your computer and use it in GitHub Desktop.
Script to search against the XML reference file for CWE records using either a CWE ID or a term.
import sys
import os
import re
from termcolor import colored
from lxml import etree
from lxml.etree import XMLParser
from pathlib import Path
"""
Script to search for CWE records using either a CWE ID or a term.
Search is performed against the XML reference file available for download here:
https://cwe.mitre.org/data/xml/cwec_latest.xml.zip
Dependencies:
pip install termcolor lxml
"""
CWE_XML_REFERENTIAL = str(Path(os.getenv("WORKSPACE_FOLDER_BASE_PATH") + "/cache/CWE/cwe.xml"))
CWE_XML_REFERENTIAL_NAMESPACES = {"cwe": "http://cwe.mitre.org/cwe-7"}
SECURE_PARSER = XMLParser(resolve_entities=False, no_network=True, load_dtd=False)
class Weakness:
id = -1
name = ""
description = ""
status = ""
mapping_usage = ""
capec_ids_list = ""
def __init__(self, cwe_node):
self.id = int(cwe_node.get("ID"))
self.name = cwe_node.get("Name")
self.status = cwe_node.get("Status").strip().lower()
self.description = cwe_node.find("cwe:Description", namespaces=CWE_XML_REFERENTIAL_NAMESPACES).text.strip()
self.description = re.sub(r'(\n|\r|\t)', '', self.description)
self.mapping_usage = cwe_node.find("cwe:Mapping_Notes", namespaces=CWE_XML_REFERENTIAL_NAMESPACES).find("cwe:Usage", namespaces=CWE_XML_REFERENTIAL_NAMESPACES).text.strip().lower()
capec_node_parent = cwe_node.find("cwe:Related_Attack_Patterns", namespaces=CWE_XML_REFERENTIAL_NAMESPACES)
capecs_ids = []
if capec_node_parent is not None:
capec_nodes = capec_node_parent.findall("cwe:Related_Attack_Pattern", namespaces=CWE_XML_REFERENTIAL_NAMESPACES)
for capec_node in capec_nodes:
capec_node_id = capec_node.get("CAPEC_ID")
capecs_ids.append(int(capec_node_id))
if len(capecs_ids) > 0:
capecs_ids.sort()
capec_ids_rendering = []
for capec_id in capecs_ids:
capec_ids_rendering.append(f"CAPEC-{capec_id}")
self.capec_ids_list = " / ".join(capec_ids_rendering)
else:
self.capec_ids_list = "None"
def get_weaknesses(search_criteria):
weaknesses = []
tree = etree.parse(CWE_XML_REFERENTIAL, parser=SECURE_PARSER)
if search_criteria.isdigit():
xpath_expr = f".//cwe:Weakness[@ID='{search_criteria}']"
else:
terms = str(search_criteria).lower().strip()
xpath_expr = f".//cwe:Weakness[contains(translate(@Name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'{terms}')]"
cwe_nodes = tree.xpath(xpath_expr, namespaces=CWE_XML_REFERENTIAL_NAMESPACES)
if cwe_nodes is not None and len(cwe_nodes) > 0:
for cwe_node in cwe_nodes:
weakness = Weakness(cwe_node)
weaknesses.append(weakness)
return weaknesses
def is_category(cwe_id):
tree = etree.parse(CWE_XML_REFERENTIAL, parser=SECURE_PARSER)
xpath_expr = f".//cwe:Category[@ID='{cwe_id}']"
cwe_nodes = tree.xpath(xpath_expr, namespaces=CWE_XML_REFERENTIAL_NAMESPACES)
return (cwe_nodes is not None and len(cwe_nodes) > 0)
def render_weaknesses(weaknesses, search_criteria):
if len(weaknesses) == 0 and search_criteria.isdigit() and is_category(search_criteria):
print(colored("⚠️ CWE ID specified is a category.", "magenta"))
print(colored(f"https://cwe.mitre.org/data/definitions/{search_criteria}.html", "cyan"))
elif len(weaknesses) == 0:
print(colored("❌ No weakness found.", "red"))
else:
for weakness in weaknesses:
print(colored(f"🐞 CWE-{weakness.id}: {weakness.name}", "yellow"))
if weakness.status == "stable":
color = "green"
else:
color = "magenta"
print(f"Status is {colored(weakness.status, color)}")
if weakness.mapping_usage.startswith("allowed"):
color = "green"
elif weakness.mapping_usage == "discouraged":
color = "red"
else:
color = "magenta"
print(f"Mapping is {colored(weakness.mapping_usage, color)}")
print(f"Related CAPEC: {weakness.capec_ids_list}")
print(colored(f"https://cwe.mitre.org/data/definitions/{weakness.id}.html", "cyan"))
print(f"{weakness.description}\n")
if len(sys.argv) < 2:
print(colored("⚠️ Missing search criteria: CWE ID or terms.", "yellow"))
else:
search_criteria = sys.argv[1]
search_criteria_type = "terms"
if search_criteria.isdigit():
search_criteria_type = "ID"
print(f"ℹ️ Search weaknesses by {search_criteria_type}.")
weaknesses = get_weaknesses(search_criteria)
render_weaknesses(weaknesses, search_criteria)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment