Commit Graph
3128 Commits
Author SHA1 Message Date
0xMarcio fca6754b6f Send stray keystrokes to the search field
Landing on the page and typing did nothing, so the first thing anyone tries
was lost and the field had to be clicked first. It is focused on load on
viewports wide enough to imply a keyboard, and typing anywhere else moves
focus there.

Focus moves during keydown rather than on the character itself, so the
keystroke that triggered it still lands in the field: typing gitea from
anywhere on the page searches for gitea, not itea. A lone slash focuses
without typing itself, and escape clears the field and steps back out.
2026-09-01 04:54:53 +02:00
0xMarcio a6be0d9794 Ignore assistant tooling
None of it is part of the project and a stray config committed once tends to
stay. The repository already had no such files tracked; this keeps it that way.
2026-09-01 04:51:07 +02:00
0xMarcio de770d6c6f Bring the site up to the README and fix the unreadable text
The page and the README had drifted into looking like two projects. The site
now opens on the same card the README banner draws, built as markup rather
than a second copy of the image, so it fills itself from the index totals the
page already loads and cannot go stale.

Contrast was the real problem. --neutral sat at 4.12:1 against the canvas,
under the 4.5 floor, and it carried the search placeholder, the star glyph and
every separator; descriptions were rendered in the muted token at 6.15:1 while
doing the work of body copy. Descriptions move to a subtle token at 12.26:1,
muted and neutral both come up, and links go to the brighter accent at 7.49:1.
The column headers were 9.5px mono under a tenth of an em of tracking, which
no contrast ratio was going to rescue.

Known-exploited CVEs are marked in the trending table too, not only inside a
result, since which row to read first is the one thing the table could not
say. The README swaps the fire emoji for the same KEV pill, served from the
repository so every flagged row points at one cached file.

The search field no longer repeats the totals now that the hero carries them,
and keeps its slot for the match timing.
2026-09-01 04:46:30 +02:00
0xMarcio b3b204bec9 Label the workflow badge CI
"Sweep" was internal vocabulary. Nobody reading the repository knows it means
the hourly job.
2026-09-01 04:32:22 +02:00
CVE-BOT cf3ea1e7b7 Trending CVEs update 2026-09-01 02:29 🤖 2026-09-01 02:29:52 +00:00
0xMarcio 2ed7386028 Give the README a banner and cut it back to the useful parts
The README opened on a bare heading and five year tables, said nothing about
what the project is, and never linked the site. Anyone landing on the repo had
to guess. It now leads with a generated banner carrying the live index totals,
a badge row, and tables trimmed to what fits a table cell.

hero.py draws the banner and the social card as self-contained SVG, since
GitHub proxies README images and drops anything the file has to fetch for
itself. It counts the corpus through build_site's own parser rather than a
second guess at what counts as a PoC, so the banner cannot drift from the site
header, and leaves the figures in docs/stats.json for the README build to
quote. If the count fails it falls back to the deployed site and, failing
that, writes nothing at all: a banner reading zero is worse than yesterday's.

Badges describing the index are baked in at build time so they always match
the banner and cannot degrade to "resource not found"; the two that describe
live GitHub state carry a stamp that defeats the image proxy cache.

The sweep now runs hourly instead of every six hours. It takes under two
minutes and the repository shows up in "recently updated" far more often.

Also adds the OpenGraph tags the site never had, so a shared link renders a
card instead of a bare URL.
2026-09-01 04:28:33 +02:00
CVE-BOT 66a8c7d36b Trending CVEs update 2026-08-31 22:09 🤖 2026-08-31 22:09:53 +00:00
CVE-BOT 34b10de390 Trending CVEs update 2026-08-31 12:05 🤖 2026-08-31 12:05:45 +00:00
CVE-BOT da494ca5b4 Drop PoC links to deleted repositories 2026-08-31 2026-08-31 11:04:40 +00:00
CVE-BOT 4e39c42af5 Update CVE PoCs 2026-08-31 2026-08-31 08:41:18 +00:00
0xMarcio 2b6547ef29 Badge known-exploited CVEs in the repository itself
KEV reached the site three days ago but nothing in the markdown said a
vulnerability was under active attack, and the repository is what most
people actually read. 1,595 entries now carry a red CISA KEV shield beside
their product and vulnerability badges, marked for ransomware use where
CISA records it.

update_cves writes the badge on entries it creates, and the weekly audit
reconciles the whole set against the refreshed catalogue, so an entry CISA
adds gains the badge and one it withdraws loses it. Re-running the sync is
a no-op.
2026-08-31 04:02:59 +02:00
0xMarcio 8c739f44e5 Reskin to GitHub Primer dark
Every colour is now a Primer dark_default token. The header band, its four
capability pills and the heading above the trending table are gone, so the
search field is the first thing on the page and the switcher labels its own
table. Rows tighten to 10px, descriptions clamp to two lines, and the PoC
list loses its box for a hairline rule.

Blue is the only thing you can click. Amber means 500 stars or more and red
means known-exploited, and nothing else carries a hue: the star glyph is
dimmed at every value so the column reads as numbers rather than symbols.

The handoff's placeholder wanted an em dash. It reads "Search CVE, vendor,
product or keyword, exclude with -windows" with the middot the count line
already uses, and the six em dashes I had left in code comments are gone
too.
2026-08-31 04:00:54 +02:00
0xMarcio abecbf733e Date a PoC by its code, not by its README
hophtien/CVE-2025-54424 led the recently-updated table claiming it was
updated 21 hours ago. The commit behind that timestamp was "Update
README.md"; the exploit itself, CVE-2025-54424.py, last changed a year
ago, and the rest of the repository six months ago.

pushed_at counts any commit, so a table built on it ranks documentation
edits as new proofs of concept. Ask GitHub for the last commit against
each root path instead and take the newest that is not paperwork, which
works for directories as well as files.

Fifty-four of this run's candidates turn out to be paperwork-only and no
longer qualify as recent, ten of the eleven for 2022. Two GraphQL rounds,
about 55 calls, 34 seconds.
2026-08-31 03:53:54 +02:00
0xMarcio 42e055b60b Sweep every reference link for rot
The first full pass over all 60,039 reference URLs: 1,566 answer 404 or
410, which removes 2,663 links from 2,419 entries and 2,445 lines from
references.txt. Anything that timed out, refused a HEAD or answered 403
kept its link.

The weekly job takes it from here on a five-week cycle, so this only had to
be paid once.
2026-08-31 03:09:10 +02:00
0xMarcio b6d3f380ca Stop paying twice for an unreachable host
A timeout kept the link either way, but the checker still followed a failed
HEAD with a GET to the same dead host, so every unreachable URL cost two
full timeouts. Return on the first network failure and drop the timeout to
eight seconds: a measured 1,500 references went from roughly three URLs a
second to fifteen.

That pass removed 98 links across 86 inventory lines, and the weekly budget
rises to 12,000 references, which sweeps the corpus every five weeks.
2026-08-31 01:45:23 +02:00
0xMarcio e9a692de92 Remove links to the retired CIS OVAL Repository
Thirty of thirty sampled returned 404: the service is gone, so all 942
links across 911 entries are permanently dead. 576 entries held nothing
else and drop out of the search index rather than offering a reader a
guaranteed miss.
2026-08-31 00:27:36 +02:00
0xMarcio 66a4f41227 Check reference links for rot, not just repositories
The audit only ever asked GitHub about repositories, leaving 60,112
reference URLs unchecked since the corpus was inherited. Sampling put hard
404s at 4%, and one host accounts for a fifth of that on its own: CIS
retired the OVAL Repository, so all 942 links to it are permanently gone
and are removed in the next commit.

The rest is diffuse, so it needs sweeping rather than a rule. Check an
eighth of the URLs each week alongside the repositories, ordered
round-robin by host so a slice does not arrive at one server as a burst.
Only a 404 or 410 removes a link: a timeout, a refused HEAD or a 403 keeps
it, and update_cves already applies the same test to references it
discovers, so this holds inherited links to the standard new ones meet.
2026-08-31 00:27:34 +02:00
0xMarcio 6822fdbfbc Fix three ways the index misread its own data
An advisory copied from a GitHub Security Advisory opens with "### Impact"
or "### Summary". The section parser treated any heading as a boundary, so
those descriptions ended themselves and reached the site empty. Only the
four headings an entry actually uses end a section now, and leading heading
markers are stripped when the text is rendered.

A trailing slash made exploit-db.com/exploits/41034 and .../41034/ two
different links, which put 53 duplicate rows in front of readers.

github.com also serves attachments and advisories, and 103 of those were
being parsed as owner/repo -- rendering "user-attachments / files" with an
empty star column instead of the PoC archive they point to.
2026-08-31 00:22:44 +02:00
0xMarcio 1aa51fa852 Mark the CVEs attackers are actually using
CISA publishes a catalogue of vulnerabilities observed being exploited in
the wild, and 1,111 of its 1,685 entries are CVEs this index already holds
PoCs for. That is the one fact a reader most wants before opening an
exploit, and it was nowhere on the page.

The weekly audit stores the catalogue, the build trims it to the CVEs the
index carries, and a result row shows a KEV chip -- with the ransomware
flag where CISA records one, which covers 352 of them. 37 KB served.

A failed fetch keeps the stored catalogue rather than dropping the badge
off every entry. The chip reuses the header pill's treatment: the palette
still spends green on things you can click and amber on star counts only.
2026-08-31 00:13:01 +02:00
0xMarcio 1377e03b6a Make the recent PoC table actually recent again
Switching the age column to the last commit left the job still sorting on
updated_at, which moves when a repository merely gains a star. The table
kept its "most recently touched" ordering while displaying commit dates,
so the front page and the README filled up with entries last worked on
122, 900 and 923 days ago.

Filter the search to repositories pushed in the last 90 days and re-sort
the pool by that same date. The API can only sort by updated_at, but a
push bumps it too, so the newest commits are always near the top of that
order and a pool of 50 per year is enough to find them.

The 2026 table now opens on a PoC pushed two days ago instead of four
months, and no row anywhere is older than the window.
2026-08-30 23:38:27 +02:00
0xMarcio 79da26dd45 Stop searching the index on every keystroke
A pass over 104,043 entries costs 25-125ms, which is fast enough to feel
instant once but not nine times in a row while a word is typed. Coalesce a
burst at 160ms, skip single-character queries that match most of the index
without narrowing anything, and total the PoC count during the scan rather
than walking the matches again to display it.
2026-08-30 23:24:19 +02:00
0xMarcio 4ec2802cf5 Drop inherited links to repositories that are not proofs of concept
The corpus was assembled by a workflow that, in its own words, output every
search result without trying to filter them. Re-checking every link whose
repository does not name its CVE against the current classifier found
27,026 of 32,675 failing it: Shodan cheat sheets under Heartbleed, FTC
robotics team repositories under the jQuery prototype pollution CVE, Docker
images matched through their dependency manifests, and a repository called
"test".

16,613 links whose repository names the CVE were never examined, a
repository that could not be fetched kept all of its links, and one that
calls itself a PoC and names the CVE is kept even where the classifier
says otherwise — deleting a real PoC costs more than leaving a doubtful
one in place.

7,223 entries lighter, and repo_meta.json drops to the 26,755
repositories still referenced.
2026-08-30 23:24:18 +02:00
0xMarcio 58c70b93ab Recognise a proof of concept written in another language
The PoC vocabulary was English-only, so a repository describing itself as
"漏洞利用" — an exploit — read as evidence that it was not one. Chinese is
the second language of this corpus by a wide margin, and the same gap
covered Spanish, Portuguese, French, Russian, Japanese and Korean.

NON_POC_RE also vetoed "prueba", which is the proof in "prueba de
concepto", inverting the signal for Spanish repositories entirely.

On the 600-repository discovery sample this admits two more genuine PoCs
and nothing else.
2026-08-30 23:24:11 +02:00
0xMarcio 368a784fe1 Rank PoC links by what they are about, not by how big they are
Sorting a CVE's links on stars alone handed the top of Log4Shell to
ThreatMapper, Viper, afrog and Awesome-OSINT-For-Everything: large tools
that mention the CVE somewhere. Rank repositories named after the CVE
first and only order those by stars, which puts CVE-2025-32463_chwoot
above a 2.5k-star general sudo toolkit.

A term no advisory text uses leaves every match tied at the weakest tier,
where newest-first is meaningless; searching log4shell led with text4shell
and then a CVE holding a single incidental link. Break those ties on how
many of the linked PoCs carry the term instead, which is only consulted
when nothing matched a description, so product searches are unchanged.

Also drop two controls that could not do anything: an expander on a
description already short enough to fit, and a footer offering to expand
a list of one.
2026-08-30 22:18:49 +02:00
CVE-BOT 77e14ec7db Trending CVEs update 2026-08-30 20:14 🤖 2026-08-30 20:14:59 +00:00
0xMarcio 066ddf4400 Rebuild the frontend to the refit design
Space Grotesk for prose, IBM Plex Mono for every identifier, and the flat
hairline-bordered surfaces from the handoff. Green marks what you can act
on and amber only ever means a star count; nothing else is coloured.

Three changes to how the same data reads. Descriptions clamp to three lines
behind an expander, so a kernel CVE no longer pushes the links people came
for below the fold. Raw URLs become owner / repo rows carrying stars and
last-commit age, ranked best first, five at a time. And an empty search box
now keeps the trending PoCs on screen with a TRENDING / RECENT toggle
rather than showing an empty page.

The search grammar, ranking and negation are unchanged.
2026-08-30 21:53:31 +02:00
0xMarcio 576b0e4735 Collect stars and last push during the weekly audit
The audit already asks GitHub about every linked repository, so the same
query can carry back a star count and a last-push date for free. Results go
to repo_meta.json, which lets a search result say which of two hundred
linked PoCs is worth opening.

2.1 MB for 45,008 repositories, refreshed weekly.
2026-08-30 21:53:20 +02:00
0xMarcio 5452bc8353 Report when a PoC repository last shipped code
The trending table sorted and displayed updated_at, which also moves when a
repository merely gains a star, so a four-month-old exploit was claiming it
had been updated three hours ago. Record pushed_at and created_at and let
the page decide: last commit for the age it shows, repository age for the
trending rank.

The job now writes trending.json alongside the README table, so the site
reads the data instead of regex-parsing markdown the same job generated.
2026-08-30 21:53:19 +02:00
0xMarcio 31c691e44f Purge dead PoC links and blank version badges
The audit found 8,404 of the 47,210 linked repositories gone from GitHub,
so 10,065 links across 5,495 entries pointed at 404s. 1,940 entries held
nothing but dead links and now carry no PoCs at all, which drops them from
the search index rather than offering a reader broken results.

The 4,733 entries whose advisory lists no affected version still rendered
an empty shields.io chip; they now read n/a like the product and
vulnerability badges beside them.
2026-08-30 21:09:52 +02:00
0xMarcio 85fe2b3ad4 Retire the abandoned second pipeline
Ten modules totalling 2,206 lines, reachable from no workflow and no live
script, alongside 18 MB of github-all.txt and references-all.txt that
nothing reads and 400 KB of stale api/v1 output that shipped in every
Pages artifact. scripts/README.md documented this as the build process.

utils.py existed for one caller and duplicated functions build_site.py
already had, so it folds into it. Nothing imports a third-party package
any more, and requirements.txt goes with it.
2026-08-30 21:09:37 +02:00
0xMarcio 6d65ae36bb Audit PoC links against GitHub weekly
Sampling the corpus put 17% of the repositories it links to behind a 404,
so readers were following links to repositories that no longer exist. The
previous audit script was 630 lines, never wired to anything, and kept its
state under a gitignored directory.

Replace it with a check that batches repository lookups through GraphQL
and removes a link only when GitHub answers NOT_FOUND for it, so a
throttle or a network error can never drop one. A quarter of the corpus
runs each week, which stays inside the token's hourly budget and sweeps
everything within the month.
2026-08-30 21:09:35 +02:00
CVE-BOT b979ae5624 Trending CVEs update 2026-08-30 15:40 🤖 2026-08-30 15:40:37 +00:00
0xMarcio 78ad23cf78 Say the CVE list is still loading instead of finding nothing
Typing before the payload arrives searched an empty dataset and reported
no results, then the loader hid the table and left a blank page, so the
query had to be typed a second time. Show that data is loading and run
the pending query once it lands.
2026-08-30 17:39:01 +02:00
0xMarcio 8dcf23b0b5 Drop PoC links filed under a truncated CVE id
Nineteen links across sixteen entries, each pointing at a repository for
an advisory whose number merely starts with the entry's own — CVE-2019-1144
holding CVE-2019-11447-POC, CVE-2023-3883 holding the WinRAR CVE-2023-38831
generator. Every one was re-checked against the classifier and none of
them survives it.
2026-08-30 17:39:00 +02:00
0xMarcio 0aa40a5f49 Reject CVE ids that are a truncation of the one a repo is about
A README caption in maniakh/CVE-2026-31431---Copy-Fail-PoC reads
"Copy Fail (CVE-2026-3143)", one digit short. That still parses as a
valid identifier, and the guard meant to catch it was satisfied by the
repo's generic exploit.py, so the PoC was filed against an unrelated
WordPress advisory. CVE-2026-8222 (Open5GS) collected a GiveWP lab the
same way. Drop an id from the same year that a longer mentioned id
extends, unless the repository name deliberately carries both.

Underscores are word characters, so the id regex matched neither half of
a name like CVE-2022-4174_CVE-2022-41742; read the separator-normalised
name too. Over 600 live candidates that recovers two real PoCs the gap
was hiding, Keycloak_CVE-2026-18963_PoC and CVE-2026-42945_NginxRift.
2026-08-30 17:38:58 +02:00
0xMarcio 56a945f9bb Rank on how well the query matches, not just whether it does
Unquoted words were scored independently, so "active directory" matched a
description holding "active session" and "working directory" as strongly
as a real AD advisory, and the newest-first tie-break then put the wrong
one on top. Reward the words appearing together.

Plain substring matching also meant "rce" hit "open source" and "sudo"
hit "pseudo"; require a term to start a word, while still allowing it to
match into one so "word" finds "wordpress". Weight matches near the start
of a description, in coarse buckets so a few characters never outweigh
recency: "log4j rce" now leads with Log4j2 rather than GeoTools.
2026-08-30 17:15:58 +02:00
CVE-BOT 9d49abebff Update CVE PoCs 2026-08-30 2026-08-30 15:06:01 +00:00
0xMarcio 68d5c9b8f4 Replay bot commits when a push is rejected
The two scheduled jobs write disjoint paths but pin their checkout when
they are queued, so a commit landing in between throws away a completed
run. Rebase onto the current main and retry instead, deepening the clone
only on the rare occasion it is needed.
2026-08-30 17:04:04 +02:00
CVE-BOT ed86403e2d Trending CVEs update 2026-08-30 15:00 🤖 2026-08-30 15:00:54 +00:00
0xMarcio 28ca54289c Untrack the generated trending file
It is rebuilt from README.md during the Pages build like CVE_list.json,
so the committed copy only ever added churn.
2026-08-30 17:00:09 +02:00
0xMarcio 7e8c22ad5f Rank search results by recency and cut page load cost
Scores were boosted by how many PoC links matched, which promoted old
CVEs with large link piles above recent findings; searching WordPress led
with 2015-2018. Rank on match quality alone and break ties by CVE year
and number, newest first.

Only the id and description are needed for every comparison, so PoC text
is derived on demand: preparing 108934 entries drops from 2.9s to 0.6s.
Dropping no-store lets the browser revalidate the 53 MB payload instead
of refetching it on every visit; the 5 KB trending file stays uncached.
Build result rows directly, since String.replace reads $& in the
replacement as a pattern, and escape link text like every other cell.
2026-08-30 16:59:43 +02:00
0xMarcio f937e5595c Authenticate the trending search and keep the token out of git
The search API was called anonymously on a 10 requests/minute limit while
the workflow already had a token; send it as an Authorization header,
never in the URL, and never print it. Dropping the token from the origin
remote also stops it being written into .git/config on the runner, since
actions/checkout already provides push credentials.

Rewrite on urllib so the job installs nothing, retry rate limits and 5xx,
and fail loudly instead of silently publishing a README with a year
missing. Repository text is flattened so a pipe cannot break the table.
2026-08-30 16:59:42 +02:00
0xMarcio f9fc5ae28d Stop tracking generated site data
Pages builds from the workflow artifact, so the committed CVE_list.json
was never served while adding a fresh 53 MB blob to history every day.
Generate it during the Pages build instead and drop the duplicate
generator; scripts/build_site.py is now the only thing that writes it.

The jinja2 templates re-rendered a trending table that logic.js replaces
on load, so the page shell goes back to being a plain static file and the
Pages build no longer installs anything. Shallow-clone the sync job too:
it never reads git history, and the three-day lookback already recovers
a skipped day.
2026-08-30 16:59:31 +02:00
0xMarcio b1ac17daf9 Widen PoC discovery and fix the empty version badge
A repository dedicated to one CVE that calls itself a PoC and ships code
was still vetoed when its description happened to contain a generic word
like writeup, patched or detector. Check the description alongside the
name for PoC intent; pure scanners that never claim to be a PoC stay out.
Measured on 600 live candidates: 15 repositories gained, none lost.

Fall back to n/a for missing versions, matching the product and
vulnerability badges instead of rendering an empty shields.io chip.
2026-08-30 16:59:13 +02:00
CVE-BOT 0c938ab939 Trending CVEs update 2026-08-30 10:52 🤖 2026-08-30 10:52:54 +00:00
CVE-BOT b1ae59882e Update CVE PoCs 2026-08-30 2026-08-30 08:21:21 +00:00
CVE-BOT 8733c5e2ae Trending CVEs update 2026-08-30 02:17 🤖 2026-08-30 02:17:03 +00:00
CVE-BOT fee3a3ee91 Trending CVEs update 2026-08-29 20:08 🤖 2026-08-29 20:08:02 +00:00
CVE-BOT f0511bf984 Trending CVEs update 2026-08-29 15:56 🤖 2026-08-29 15:56:31 +00:00
CVE-BOT 113f67cb64 Trending CVEs update 2026-08-29 11:55 🤖 2026-08-29 11:55:57 +00:00