Repository navigation
Expand file tree
/
Copy pathsearch.py
More file actions
140 lines (114 loc) · 5 KB
/
Copy pathsearch.py
File metadata and controls
140 lines (114 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env python3
"""
CVE-2026-PoCs Local Search Utility
Instantly search 3,300+ CVE Proof-of-Concepts by CVE number, vendor, product, or vulnerability class.
Usage:
python search.py <keyword or CVE ID>
python search.py 76504
python search.py cisco --min-cvss 9.0
python search.py wordpress --critical
"""
import sys
import os
import re
import argparse
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
WORKSPACE_DIR = os.path.dirname(os.path.abspath(__file__))
INDEX_PATH = os.path.join(WORKSPACE_DIR, "INDEX.md")
# ANSI color codes for terminal display
RED = "\033[91m"
YELLOW = "\033[93m"
GREEN = "\033[92m"
CYAN = "\033[96m"
BOLD = "\033[1m"
RESET = "\033[0m"
def load_entries():
"""Parse CVE entries from INDEX.md table."""
entries = []
if not os.path.exists(INDEX_PATH):
print(f"{RED}[!] Error: {INDEX_PATH} not found. Run scripts/generate_index.py first.{RESET}")
return entries
table_started = False
with open(INDEX_PATH, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
line = line.strip()
if "| CVE ID |" in line:
table_started = True
continue
if table_started and line.startswith("|") and not line.startswith("|---"):
parts = [p.strip() for p in line.split("|")[1:-1]]
if len(parts) >= 7:
# parts: [CVE Link, CVSS, Vendor/Product, Vuln Class, Day, Status, Added]
cve_match = re.search(r'\[(CVE-2026-\d+)\]\((.*?)\)', parts[0])
cve_id = cve_match.group(1) if cve_match else parts[0]
cve_path = cve_match.group(2) if cve_match else f"2026/{cve_id}"
cvss_raw = parts[1]
cvss_match = re.search(r'(\d+\.\d+)', cvss_raw)
cvss_val = float(cvss_match.group(1)) if cvss_match else 0.0
entries.append({
"id": cve_id,
"path": cve_path,
"cvss_badge": parts[1],
"cvss": cvss_val,
"product": parts[2],
"vuln": parts[3],
"status": parts[5],
"added": parts[6]
})
return entries
def main():
parser = argparse.ArgumentParser(
description="Search CVE-2026-PoCs repository by name, number, or severity."
)
parser.add_argument("query", nargs="?", default="", help="Search query (e.g. 'cisco', '76504', 'kernel')")
parser.add_argument("--cve", help="Filter specifically by CVE ID / number")
parser.add_argument("--product", help="Filter by product or vendor name")
parser.add_argument("--min-cvss", type=float, default=0.0, help="Minimum CVSS score (e.g. 8.0, 9.0)")
parser.add_argument("--critical", action="store_true", help="Only show Critical severity (CVSS >= 9.0)")
parser.add_argument("--limit", type=int, default=25, help="Maximum results to display (default: 25)")
args = parser.parse_args()
entries = load_entries()
if not entries:
print(f"{RED}[!] No entries loaded.{RESET}")
sys.exit(1)
min_cvss = 9.0 if args.critical else args.min_cvss
query = (args.query or "").strip().lower()
# Normalize pure numbers like '76504' to match 'CVE-2026-76504'
results = []
for e in entries:
if e["cvss"] < min_cvss:
continue
if args.cve and args.cve.lower() not in e["id"].lower():
continue
if args.product and args.product.lower() not in e["product"].lower():
continue
if query:
match_id = query in e["id"].lower() or query in e["id"].replace("CVE-2026-", "").lower()
match_prod = query in e["product"].lower()
match_vuln = query in e["vuln"].lower()
if not (match_id or match_prod or match_vuln):
continue
results.append(e)
# Display results
print(f"\n{BOLD}{CYAN}🔍 Found {len(results)} matching CVEs{RESET} (showing top {min(len(results), args.limit)}):")
print(f"{'CVE ID':<18} {'CVSS':<8} {'Product / Component':<32} {'Vulnerability Class':<35} {'Local Path'}")
print("-" * 115)
for e in results[:args.limit]:
score_str = f"{e['cvss']:.1f}" if e['cvss'] > 0 else "—"
if e["cvss"] >= 9.0:
score_disp = f"{RED}{score_str:<6}{RESET}"
elif e["cvss"] >= 7.0:
score_disp = f"{YELLOW}{score_str:<6}{RESET}"
else:
score_disp = f"{GREEN}{score_str:<6}{RESET}"
prod_disp = e['product'][:30]
vuln_disp = e['vuln'][:33]
print(f"{BOLD}{e['id']:<18}{RESET} {score_disp} {prod_disp:<32} {vuln_disp:<35} {e['path']}")
print("-" * 115)
if len(results) > args.limit:
print(f"{YELLOW}[*] {len(results) - args.limit} more results not shown. Use --limit {len(results)} to view all.{RESET}\n")
else:
print()
if __name__ == "__main__":
main()