diff --git a/.github/getTrending.py b/.github/getTrending.py index 130011ca4f8..fe9d06831a2 100644 --- a/.github/getTrending.py +++ b/.github/getTrending.py @@ -481,6 +481,54 @@ def live_pill(path: str, label: str, colour: str, link: str, stamp: str) -> str: f"&labelColor=161b22&_={stamp})]({link})") +def count_stamp(counts: dict) -> str: + keys = ("total_cves", "with_pocs", "kev") + if any(not counts.get(key) for key in keys): + raise RuntimeError("docs/stats.json does not contain usable corpus counts") + return "-".join(str(int(counts[key])) for key in keys) + + +def refresh_count_header() -> int: + """Update only the README figures after a corpus-changing sync.""" + counts = figures() + stamp = count_stamp(counts) + with open(README, encoding="utf-8") as handle: + content = handle.read() + + content, hero_replacements = re.subn( + rf"({re.escape(HERO_URL)}\?v=)[^\"]+", + rf"\g<1>{stamp}", + content, + count=1, + ) + badges = { + "CVEs with PoCs": pill( + "CVEs with PoCs", f"{counts['with_pocs']:,}", "2f81f7", + "https://cve.codepwn.win/", + ), + "known exploited": pill( + "known exploited", f"{counts['kev']:,}", "f85149", + "https://cve.codepwn.win/", + ), + } + badge_replacements = 0 + for label, badge in badges.items(): + content, replaced = re.subn( + rf"\[!\[{re.escape(label)}\]\([^)]+\)\]\([^)]+\)", + lambda _: badge, + content, + count=1, + ) + badge_replacements += replaced + if hero_replacements != 1 or badge_replacements != len(badges): + raise RuntimeError("README count header is missing an expected field") + + with open(README, "w", encoding="utf-8") as handle: + handle.write(content) + print(f"Updated README counts to {stamp}") + return 0 + + def header(stamp: str, synced: str) -> list[str]: """Everything above the tables. The banner carries a cache-busting stamp because GitHub proxies README images and would otherwise serve a stale copy @@ -501,10 +549,12 @@ def header(stamp: str, synced: str) -> list[str]: return [ '
', "", - f'CVE Radar', + f'CVE Radar', "", " ".join(badges), "", + f'cve.codepwn.win', + "", "
", "", ] @@ -665,15 +715,8 @@ def main() -> int: # No hyphens: they are the field separator in a shields badge path. synced = now.strftime("%d %b %Y %H:%M UTC") lines = header(stamp, synced) - lines.append(f"Exploit repositories with a commit in the last {WINDOW_DAYS} days, " - f"newest first. {KEV_MARK.strip()} marks a CVE CISA lists as " - f"exploited in the wild.") - lines.append("") if landed: - lines.append(f"## Just landed · last {LANDED_DAYS} days") - lines.append("") - lines.append("No star floor here, so a PoC published this morning shows up " - "the same day rather than once it has been noticed.") + lines.append("## Just landed") lines.append("") lines.append("| Stars | Updated | Repository | Description |") lines.append("| --- | --- | --- | --- |") @@ -727,4 +770,9 @@ def main() -> int: if __name__ == "__main__": + if sys.argv[1:] == ["--counts-only"]: + raise SystemExit(refresh_count_header()) + if sys.argv[1:]: + print("usage: getTrending.py [--counts-only]", file=sys.stderr) + raise SystemExit(2) raise SystemExit(main()) diff --git a/.github/workflows/audit_poc_links.yml b/.github/workflows/audit_poc_links.yml index b4d084473af..329ca96e4bb 100644 --- a/.github/workflows/audit_poc_links.yml +++ b/.github/workflows/audit_poc_links.yml @@ -32,6 +32,11 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: python3 scripts/audit_poc_links.py --limit 12000 --references 12000 + - name: Refresh published counts + run: | + python3 .github/hero.py + python3 .github/getTrending.py --counts-only + - name: Check for changes and commit run: | git config user.name 'CVE-BOT' @@ -43,6 +48,10 @@ jobs: index/repo_meta.json \ index/kev.json \ index/references.txt \ + README.md \ + docs/hero.svg \ + docs/social-card.svg \ + docs/stats.json \ cves/ if git diff --cached --quiet; then diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml index 591f76a0e1b..59e7bf31575 100644 --- a/.github/workflows/site.yml +++ b/.github/workflows/site.yml @@ -32,6 +32,16 @@ jobs: - name: Build site data run: python3 scripts/build_site.py + - name: Verify published counts + run: | + python3 .github/hero.py + python3 .github/getTrending.py --counts-only + git diff --exit-code -- \ + README.md \ + docs/hero.svg \ + docs/social-card.svg \ + docs/stats.json + - name: Configure Pages uses: actions/configure-pages@v6 diff --git a/.github/workflows/sync_collections.yml b/.github/workflows/sync_collections.yml index b9cc092e46b..8b975ba4c05 100644 --- a/.github/workflows/sync_collections.yml +++ b/.github/workflows/sync_collections.yml @@ -32,11 +32,23 @@ jobs: python3 -m unittest discover -s tests python3 scripts/build_site.py + - name: Refresh published counts + run: | + python3 .github/hero.py + python3 .github/getTrending.py --counts-only + - name: Check for changes and commit run: | git config user.name 'CVE-BOT' git config user.email 'cve@codepwn.win' - git add --all -- index/cve_dates.json index/cve_record_state.json cves/ + git add --all -- \ + README.md \ + docs/hero.svg \ + docs/social-card.svg \ + docs/stats.json \ + index/cve_dates.json \ + index/cve_record_state.json \ + cves/ if git diff --cached --quiet; then echo "No changes to commit" diff --git a/.github/workflows/sync_cve_pocs.yml b/.github/workflows/sync_cve_pocs.yml index 11b337e2aa6..2258a39e702 100644 --- a/.github/workflows/sync_cve_pocs.yml +++ b/.github/workflows/sync_cve_pocs.yml @@ -34,6 +34,11 @@ jobs: python3 -m unittest discover -s tests python3 scripts/build_site.py + - name: Refresh published counts + run: | + python3 .github/hero.py + python3 .github/getTrending.py --counts-only + - name: Check for changes and commit run: | git config user.name 'CVE-BOT' @@ -46,6 +51,10 @@ jobs: index/reference_pocs.txt \ index/cve_dates.json \ index/cve_record_state.json \ + README.md \ + docs/hero.svg \ + docs/social-card.svg \ + docs/stats.json \ cves/ if git diff --cached --quiet; then diff --git a/.github/workflows/sync_exploits.yml b/.github/workflows/sync_exploits.yml index 9a7a564f5a8..a70a38f4513 100644 --- a/.github/workflows/sync_exploits.yml +++ b/.github/workflows/sync_exploits.yml @@ -32,11 +32,23 @@ jobs: python3 -m unittest discover -s tests python3 scripts/build_site.py + - name: Refresh published counts + run: | + python3 .github/hero.py + python3 .github/getTrending.py --counts-only + - name: Check for changes and commit run: | git config user.name 'CVE-BOT' git config user.email 'cve@codepwn.win' - git add --all -- index/cve_dates.json index/cve_record_state.json cves/ + git add --all -- \ + README.md \ + docs/hero.svg \ + docs/social-card.svg \ + docs/stats.json \ + index/cve_dates.json \ + index/cve_record_state.json \ + cves/ if git diff --cached --quiet; then echo "No changes to commit" diff --git a/.github/workflows/sync_metadata.yml b/.github/workflows/sync_metadata.yml index 75fbcbe8943..e2bf9d2b661 100644 --- a/.github/workflows/sync_metadata.yml +++ b/.github/workflows/sync_metadata.yml @@ -49,12 +49,21 @@ jobs: python3 -m unittest discover -s tests python3 scripts/build_site.py + - name: Refresh published counts + run: | + python3 .github/hero.py + python3 .github/getTrending.py --counts-only + - name: Check for changes and commit run: | git config user.name 'CVE-BOT' git config user.email 'cve@codepwn.win' git add -- \ + README.md \ cves/ \ + docs/hero.svg \ + docs/social-card.svg \ + docs/stats.json \ index/cve_dates.json \ index/cve_record_state.json \ index/github_advisories.json \ diff --git a/.github/workflows/sync_nuclei.yml b/.github/workflows/sync_nuclei.yml index e8fa05be947..fa89c1e4c35 100644 --- a/.github/workflows/sync_nuclei.yml +++ b/.github/workflows/sync_nuclei.yml @@ -32,11 +32,24 @@ jobs: python3 -m unittest discover -s tests python3 scripts/build_site.py + - name: Refresh published counts + run: | + python3 .github/hero.py + python3 .github/getTrending.py --counts-only + - name: Check for changes and commit run: | git config user.name 'CVE-BOT' git config user.email 'cve@codepwn.win' - git add --all -- index/cve_dates.json index/cve_record_state.json index/nuclei.json cves/ + git add --all -- \ + README.md \ + docs/hero.svg \ + docs/social-card.svg \ + docs/stats.json \ + index/cve_dates.json \ + index/cve_record_state.json \ + index/nuclei.json \ + cves/ if git diff --cached --quiet; then echo "No changes to commit" exit 0 diff --git a/.github/workflows/sync_pocingithub.yml b/.github/workflows/sync_pocingithub.yml index 4d6ee8b6ef0..d4fc61c2559 100644 --- a/.github/workflows/sync_pocingithub.yml +++ b/.github/workflows/sync_pocingithub.yml @@ -38,11 +38,24 @@ jobs: python3 -m unittest discover -s tests python3 scripts/build_site.py + - name: Refresh published counts + run: | + python3 .github/hero.py + python3 .github/getTrending.py --counts-only + - name: Check for changes and commit run: | git config user.name 'CVE-BOT' git config user.email 'cve@codepwn.win' - git add --all -- index/github.txt index/cve_dates.json index/cve_record_state.json cves/ + git add --all -- \ + README.md \ + docs/hero.svg \ + docs/social-card.svg \ + docs/stats.json \ + index/github.txt \ + index/cve_dates.json \ + index/cve_record_state.json \ + cves/ if git diff --cached --quiet; then echo "No changes to commit" diff --git a/README.md b/README.md index 8752c056efb..2510e18ff55 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,14 @@
-CVE Radar +CVE Radar -[![last sync](https://img.shields.io/badge/last%20sync-01%20Sep%202026%2022%3A40%20UTC-2f81f7?style=flat-square&labelColor=161b22)](https://github.com/0xMarcio/cve/commits/main) [![CI](https://img.shields.io/github/actions/workflow/status/0xMarcio/cve/hot_cves.yml?style=flat-square&label=CI&color=2f81f7&labelColor=161b22&_=202609012240)](https://github.com/0xMarcio/cve/actions/workflows/hot_cves.yml) [![CVEs with PoCs](https://img.shields.io/badge/CVEs%20with%20PoCs-91%2C895-2f81f7?style=flat-square&labelColor=161b22)](https://cve.codepwn.win/) [![known exploited](https://img.shields.io/badge/known%20exploited-1%2C190-f85149?style=flat-square&labelColor=161b22)](https://cve.codepwn.win/) [![stars](https://img.shields.io/github/stars/0xMarcio/cve?style=flat-square&label=stars&color=e3b341&labelColor=161b22&_=202609012240)](https://github.com/0xMarcio/cve/stargazers) +[![last sync](https://img.shields.io/badge/last%20sync-01%20Sep%202026%2022%3A40%20UTC-2f81f7?style=flat-square&labelColor=161b22)](https://github.com/0xMarcio/cve/commits/main) [![CI](https://img.shields.io/github/actions/workflow/status/0xMarcio/cve/hot_cves.yml?style=flat-square&label=CI&color=2f81f7&labelColor=161b22&_=202609012240)](https://github.com/0xMarcio/cve/actions/workflows/hot_cves.yml) [![CVEs with PoCs](https://img.shields.io/badge/CVEs%20with%20PoCs-82%2C409-2f81f7?style=flat-square&labelColor=161b22)](https://cve.codepwn.win/) [![known exploited](https://img.shields.io/badge/known%20exploited-1%2C181-f85149?style=flat-square&labelColor=161b22)](https://cve.codepwn.win/) [![stars](https://img.shields.io/github/stars/0xMarcio/cve?style=flat-square&label=stars&color=e3b341&labelColor=161b22&_=202609012240)](https://github.com/0xMarcio/cve/stargazers) + +cve.codepwn.win
-Exploit repositories with a commit in the last 90 days, newest first. KEV marks a CVE CISA lists as exploited in the wild. - -## Just landed · last 10 days - -No star floor here, so a PoC published this morning shows up the same day rather than once it has been noticed. +## Just landed | Stars | Updated | Repository | Description | | --- | --- | --- | --- | diff --git a/docs/hero.svg b/docs/hero.svg index 26db5c2432a..39f1d244a13 100644 --- a/docs/hero.svg +++ b/docs/hero.svg @@ -1,5 +1,5 @@ + role="img" aria-label="CVE Radar, 82,409 CVEs with public proof-of-concept exploits"> @@ -19,13 +19,13 @@ cve.codepwn.win 168,780 + fill="#e6edf3" letter-spacing="-0.5">170,946 CVES INDEXED91,895 + fill="#2f81f7" letter-spacing="-0.5">82,409 WITH POCS1,190 + fill="#f85149" letter-spacing="-0.5">1,181 KNOWN EXPLOITED diff --git a/docs/social-card.svg b/docs/social-card.svg index ac1a9ecc197..1133f78ee8d 100644 --- a/docs/social-card.svg +++ b/docs/social-card.svg @@ -20,13 +20,13 @@ 168,780 + fill="#e6edf3" letter-spacing="-0.5">170,946 CVES INDEXED91,895 + fill="#2f81f7" letter-spacing="-0.5">82,409 WITH POCS1,190 + fill="#f85149" letter-spacing="-0.5">1,181 KNOWN EXPLOITED diff --git a/docs/stats.json b/docs/stats.json index 7324c23935c..61c52dea08d 100644 --- a/docs/stats.json +++ b/docs/stats.json @@ -1,5 +1,5 @@ { - "kev": 1190, - "total_cves": 168780, - "with_pocs": 91895 + "kev": 1181, + "total_cves": 170946, + "with_pocs": 82409 }