diff --git a/.github/getTrending.py b/.github/getTrending.py index edc89cfa93..3fca31f89f 100644 --- a/.github/getTrending.py +++ b/.github/getTrending.py @@ -1,99 +1,114 @@ #!/usr/bin/env python3 -# -*- coding:utf-8 -*- +"""Regenerate the Trending PoCs table in README.md. + +- Only consider repositories whose names contain the current year's CVE pattern (e.g., CVE-2025-1234). +- Restrict to repositories updated in the last 4 days. +- Sort by most recently updated, then stars, and emit up to 20 rows. +""" + +from __future__ import annotations + +import os +import re +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Iterable, List, TypedDict + import requests -import json -from datetime import datetime + +WINDOW_DAYS = 4 +MAX_ROWS = 20 -def time_ago(datetime_str): - datetime_obj = datetime.strptime(datetime_str, "%Y-%m-%dT%H:%M:%SZ") - current_datetime = datetime.now() - delta = current_datetime - datetime_obj +class Repo(TypedDict): + name: str + html_url: str + description: str | None + stargazers_count: int + updated_at: str + + +def github_headers() -> dict: + token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN") + headers = {"Accept": "application/vnd.github+json"} + if token: + headers["Authorization"] = f"Bearer {token}" + return headers + + +def time_ago(updated_at: str, now: datetime) -> str: + dt = datetime.strptime(updated_at, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc) + delta = now - dt if delta.days > 0: - if delta.days == 1: - return "1 day ago" - else: - return f"{delta.days} days ago" - elif delta.seconds >= 3600: - hours = delta.seconds // 3600 - if hours == 1: - return "1 hour ago" - else: - return f"{hours} hours ago" - elif delta.seconds >= 60: - minutes = delta.seconds // 60 - if minutes == 1: - return "1 minute ago" - else: - return f"{minutes} minutes ago" + return "1 day ago" if delta.days == 1 else f"{delta.days} days ago" + hours = delta.seconds // 3600 + if hours: + return "1 hour ago" if hours == 1 else f"{hours} hours ago" + minutes = (delta.seconds % 3600) // 60 + if minutes: + return "1 minute ago" if minutes == 1 else f"{minutes} minutes ago" + return "just now" + + +def fetch_trending(current_year: int, cutoff: datetime) -> List[Repo]: + query = f"CVE-{current_year} in:name stars:>2 pushed:>={cutoff.date().isoformat()} archived:false" + url = "https://api.github.com/search/repositories" + params = { + "q": query, + "sort": "updated", + "order": "desc", + "per_page": 100, + "page": 1, + } + resp = requests.get(url, params=params, headers=github_headers(), timeout=30) + resp.raise_for_status() + items: Iterable[Repo] = resp.json().get("items", []) + pattern = re.compile(rf"cve-{current_year}-\d+", re.IGNORECASE) + filtered: List[Repo] = [] + for item in items: + name = item.get("name", "") + updated_at = item.get("updated_at") + if not updated_at or not pattern.search(name or ""): + continue + updated_dt = datetime.strptime(updated_at, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc) + if updated_dt < cutoff: + continue + filtered.append(item) + # Already sorted by updated desc; break ties by stars + filtered.sort(key=lambda r: (-datetime.strptime(r["updated_at"], "%Y-%m-%dT%H:%M:%SZ").timestamp(), -int(r.get("stargazers_count", 0)))) + return filtered[:MAX_ROWS] + + +def build_rows(repos: List[Repo], now: datetime) -> List[str]: + rows: List[str] = [] + for repo in repos: + desc = repo.get("description") or "" + stars = int(repo.get("stargazers_count", 0)) + updated = time_ago(repo["updated_at"], now) + rows.append(f"| {stars}⭐ | {updated} | [{repo['name']}]({repo['html_url']}) | {desc} |") + return rows + + +def main() -> None: + current_year = datetime.now(timezone.utc).year + cutoff = datetime.now(timezone.utc) - timedelta(days=WINDOW_DAYS) + now = datetime.now(timezone.utc) + + repos = fetch_trending(current_year, cutoff) + + output: List[str] = ['
| Stars | Updated | Name | Description | ||||
|---|---|---|---|---|---|---|---|
| 1241 | +360 | 2 hours ago | -CVE-2025-55182 | -Explanation and full RCE PoC for CVE-2025-55182 | -|||
| 775 | -3 hours ago | -CVE-2025-55182-research | -CVE-2025-55182 POC | -||||
| 495 | -8 days ago | -CVE-2018-20250 | -exp for https://research.checkpoint.com/extracting-code-execution-from-winrar | -||||
| 607 | -20 hours ago | -CVE-2025-33073 | -PoC Exploit for the NTLM reflection SMB flaw. | -||||
| 496 | -4 days ago | -CVE-2025-32463_chwoot | -Escalation of Privilege to the root through sudo binary with chroot option. CVE-2025-32463 | -||||
| 419 | -5 hours ago | -CVE-2025-32463 | -Local Privilege Escalation to Root via Sudo chroot in Linux | -||||
| 305 | -1 day ago | -CVE-2025-53770-Exploit | -SharePoint WebPart Injection Exploit Tool | -||||
| 289 | -4 hours ago | -CVE-2025-55182 | -RSC/Next.js RCE Vulnerability Detector & PoC Chrome Extension – CVE-2025-55182 & CVE-2025-66478 | -||||
| 901 | -1 hour ago | -React2Shell-CVE-2025-55182-original-poc | -Original Proof-of-Concepts for React2Shell CVE-2025-55182 | -||||
| 386 | -4 days ago | -CVE-2025-24071_PoC | -CVE-2025-24071: NTLM Hash Leak via RAR/ZIP Extraction and .library-ms File | -||||
| 207 | -1 day ago | -CVE-2025-32023 | -PoC & Exploit for CVE-2025-32023 / PlaidCTF 2025 "Zerodeo" | -||||
| 396 | -6 days ago | -ColorOS-CVE-2025-10184 | -ColorOS短信漏洞,以及用户自救方案 | -||||
| 180 | -6 days ago | -POC-CVE-2025-24813 | -his repository contains an automated Proof of Concept (PoC) script for exploiting **CVE-2025-24813**, a Remote Code Execution (RCE) vulnerability in Apache Tomcat. The vulnerability allows an attacker to upload a malicious serialized payload to the server, leading to arbitrary code execution via deserialization when specific conditions are met. | -||||
| 256 | -15 minutes ago | -CVE-2025-55182-advanced-scanner- | -- | ||||
| 357 | -1 hour ago | Next.js-RSC-RCE-Scanner-CVE-2025-66478 | A command-line scanner for batch detection of Next.js application versions and determining if they are affected by CVE-2025-66478 vulnerability. | ||||
| 198 | -4 days ago | -CVE-2025-30208-EXP | -CVE-2025-30208-EXP | +4 | +13 hours ago | +CVE-2025-66478-POC | +CVE-2025-66478 Proof of Concept |
| 73 | -6 days ago | -cve-2025-8088 | -Path traversal tool based on cve-2025-8088 | +4 | +22 hours ago | +CVE-2025-65318-and-CVE-2025-65319 | +Insecure attachment handling when using Canary Mail or Blue mail |
| 163 | +78 | 1 day ago | -CVE-2025-26125 | -( 0day ) Local Privilege Escalation in IObit Malware Fighter | +Blackash-CVE-2025-55182 | +CVE-2025-55182 | |
| 153 | -8 days ago | -CVE-2025-21756 | -Exploit for CVE-2025-21756 for Linux kernel 6.6.75. My first linux kernel exploit! | +17 | +1 day ago | +CVE-2025-55182 | +a critical Remote Code Execution (RCE) vulnerability in React Server Components (RSC). It also includes a realistic "Lab Environment" to safely test and understand the vulnerability. |
| 136 | -27 days ago | -CVE-2025-32433 | -CVE-2025-32433 https://github.com/erlang/otp/security/advisories/GHSA-37cp-fgq5-7wc2 | +6 | +1 day ago | +CVE-2025-55184-POC-Expolit | ++ |
| 3 | +1 day ago | +CVE-2025-54100 | +CVE-2025-54100 (CVSS 7.8 High) is a command injection vulnerability in the Invoke-WebRequest cmdlet of Windows PowerShell 5.1. It arises from improper neutralization of special elements during the automatic parsing of Web responses. | +||||
| 5 | +3 days ago | +CVE-2025-55182-golang-PoC | +CVE-2025-55182 React Server Components RCE - Go PoC |