mirror of
https://github.com/0x5t4l1n/CVE.git
synced 2026-05-26 11:25:49 +00:00
feat: add workflow and script to auto-update README when CVE files change
Agent-Logs-Url: https://github.com/Stalin-143/CVE/sessions/23d694ad-2e83-44ad-b08e-57dd48698eac Co-authored-by: Stalin-143 <161853795+Stalin-143@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
4fb6319d26
commit
066486aec1
@@ -0,0 +1,41 @@
|
|||||||
|
name: Auto-update README on CVE changes
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "reported/**"
|
||||||
|
- "patches/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-readme:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.x"
|
||||||
|
|
||||||
|
- name: Update README.md
|
||||||
|
run: python scripts/update_readme.py
|
||||||
|
|
||||||
|
- name: Commit and push if README changed
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add README.md
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
echo "No changes to README.md — skipping commit."
|
||||||
|
else
|
||||||
|
git commit -m "docs: auto-update README CVE tables"
|
||||||
|
git push
|
||||||
|
fi
|
||||||
@@ -13,9 +13,9 @@ CVEs that were discovered and reported by Stalin S.
|
|||||||
|
|
||||||
| CVE | Description | Severity |
|
| CVE | Description | Severity |
|
||||||
|-----|-------------|----------|
|
|-----|-------------|----------|
|
||||||
| [CVE-2026-29905](reported/CVE-2026-29905.md) | Kirby CMS — Persistent DoS via Malformed Image Upload | Medium |
|
| [CVE-2026-29905](reported/CVE-2026-29905.md) | Kirby CMS Persistent DoS via Malformed Image Upload | Medium |
|
||||||
| [CVE-2026-41037](reported/CVE-2026-41037.md) | Quantum Networks Router — Missing Rate Limiting | High |
|
| [CVE-2026-41037](reported/CVE-2026-41037.md) | Missing Rate Limiting (Quantum Networks Router) | High (8.7) |
|
||||||
| [CVE-2026-41039](reported/CVE-2026-41039.md) | Quantum Networks Router — Information Disclosure | High |
|
| [CVE-2026-41039](reported/CVE-2026-41039.md) | Information Disclosure (Quantum Networks Router) | High (8.7) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -25,6 +25,6 @@ CVEs where Stalin S fixed the security issue.
|
|||||||
|
|
||||||
| CVE | Description | Severity |
|
| CVE | Description | Severity |
|
||||||
|-----|-------------|----------|
|
|-----|-------------|----------|
|
||||||
| [CVE-2026-32138](patches/CVE-2026-32138.md) | Nexulean Website — API Key Exposure | High |
|
| [CVE-2026-32138](patches/CVE-2026-32138.md) | API Key Exposure (Nexulean Website) | High |
|
||||||
| [CVE-2026-41575](patches/CVE-2026-41575.md) | IP Reputation Checker — DOM-Based XSS | Moderate |
|
| [CVE-2026-41575](patches/CVE-2026-41575.md) | DOM-Based XSS (IP Reputation Checker) | Moderate |
|
||||||
| [CVE-2026-41900](patches/CVE-2026-41900.md) | OpenLearnX — RCE via Sandbox Escape | High |
|
| [CVE-2026-41900](patches/CVE-2026-41900.md) | RCE via Sandbox Escape (OpenLearnX) | High |
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Scans the reported/ and patches/ directories for CVE markdown files,
|
||||||
|
extracts CVE ID, description, and severity, then rewrites the
|
||||||
|
Reported and Patched tables in README.md automatically.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
README_PATH = os.path.join(REPO_ROOT, "README.md")
|
||||||
|
REPORTED_DIR = os.path.join(REPO_ROOT, "reported")
|
||||||
|
PATCHES_DIR = os.path.join(REPO_ROOT, "patches")
|
||||||
|
|
||||||
|
|
||||||
|
def extract_info(filepath: str) -> dict:
|
||||||
|
"""Return {cve_id, description, severity} parsed from a CVE markdown file."""
|
||||||
|
with open(filepath, encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# CVE ID from filename (most reliable source)
|
||||||
|
filename = os.path.basename(filepath)
|
||||||
|
cve_id = re.sub(r"\.md$", "", filename, flags=re.IGNORECASE)
|
||||||
|
|
||||||
|
# Description: grab from the first level-1 heading, strip the CVE prefix
|
||||||
|
description = ""
|
||||||
|
heading_match = re.search(r"^#\s+(?:CVE-[\d-]+\s*[—–-]+\s*)?(.*)", content, re.MULTILINE)
|
||||||
|
if heading_match:
|
||||||
|
description = heading_match.group(1).strip()
|
||||||
|
|
||||||
|
# Severity: look for bold label **Severity:** value (same line or next word)
|
||||||
|
severity = "N/A"
|
||||||
|
sev_match = re.search(
|
||||||
|
r"\*\*Severity:\*\*\s*([^\n|]+)", content, re.IGNORECASE
|
||||||
|
)
|
||||||
|
if sev_match:
|
||||||
|
severity = sev_match.group(1).strip().rstrip("\\").strip()
|
||||||
|
|
||||||
|
return {"cve_id": cve_id, "description": description, "severity": severity}
|
||||||
|
|
||||||
|
|
||||||
|
def build_table(entries: list, folder: str) -> str:
|
||||||
|
"""Build a markdown table string from a list of entry dicts."""
|
||||||
|
lines = [
|
||||||
|
"| CVE | Description | Severity |",
|
||||||
|
"|-----|-------------|----------|",
|
||||||
|
]
|
||||||
|
for e in entries:
|
||||||
|
cve_link = f"[{e['cve_id']}]({folder}/{e['cve_id']}.md)"
|
||||||
|
lines.append(f"| {cve_link} | {e['description']} | {e['severity']} |")
|
||||||
|
# trailing newline preserves the blank line before the next `---` separator
|
||||||
|
return "\n".join(lines) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def collect_entries(directory: str) -> list:
|
||||||
|
"""Return sorted list of entry dicts for all CVE .md files in a directory."""
|
||||||
|
entries = []
|
||||||
|
if not os.path.isdir(directory):
|
||||||
|
return entries
|
||||||
|
for fname in sorted(os.listdir(directory)):
|
||||||
|
if re.match(r"CVE-\d+-\d+\.md$", fname, re.IGNORECASE):
|
||||||
|
fpath = os.path.join(directory, fname)
|
||||||
|
entries.append(extract_info(fpath))
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
def update_readme(reported_entries: list, patched_entries: list) -> None:
|
||||||
|
"""Replace the Reported and Patched tables in README.md."""
|
||||||
|
with open(README_PATH, encoding="utf-8") as f:
|
||||||
|
readme = f.read()
|
||||||
|
|
||||||
|
reported_table = build_table(reported_entries, "reported")
|
||||||
|
patched_table = build_table(patched_entries, "patches")
|
||||||
|
|
||||||
|
# Pattern: from the table header row up to (but not including) the next heading or end
|
||||||
|
table_pattern = r"(\| CVE \| Description \| Severity \|.*?)(?=\n---|\n##|\Z)"
|
||||||
|
|
||||||
|
tables_found = re.findall(table_pattern, readme, flags=re.DOTALL)
|
||||||
|
if len(tables_found) < 2:
|
||||||
|
print("ERROR: Could not locate both tables in README.md", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Replace first table occurrence (Reported), then second (Patched)
|
||||||
|
new_readme = readme
|
||||||
|
# Use a counter-based replacement to replace occurrences independently
|
||||||
|
count = [0]
|
||||||
|
|
||||||
|
def replacer(m):
|
||||||
|
count[0] += 1
|
||||||
|
if count[0] == 1:
|
||||||
|
return reported_table
|
||||||
|
return patched_table
|
||||||
|
|
||||||
|
new_readme = re.sub(table_pattern, replacer, readme, flags=re.DOTALL)
|
||||||
|
|
||||||
|
with open(README_PATH, "w", encoding="utf-8") as f:
|
||||||
|
f.write(new_readme)
|
||||||
|
|
||||||
|
print(f"README.md updated: {len(reported_entries)} reported, {len(patched_entries)} patched.")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
reported = collect_entries(REPORTED_DIR)
|
||||||
|
patched = collect_entries(PATCHES_DIR)
|
||||||
|
update_readme(reported, patched)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user