bounty-slop-watch
A public health board for bug-bounty programs in the AI-slop era. Independent
security researchers and OSS maintainers can see which HackerOne / Bugcrowd
programs are still paying, which paused intake, and which explicitly banned
AI-generated reports — before they spend a week writing a report nobody will read.
The site nightly scrapes the public HackerOne and Bugcrowd directories,
classifies each program with a small keyword-rule engine, and surfaces:
- Healthiest — top 20 active programs sorted by bounty ceiling
- Casualties — programs that closed, paused, or banned AI in the last 30 days
- AI restrictions — programs that explicitly restrict or ban AI-generated reports
- All programs — every program we've ever indexed, filterable
- Scrape transparency — every cron run, success or failure
Each program has an embeddable SVG badge (/badge/:platform/:handle.svg) and an
RSS feed (/feed.xml) so the data flows out of the site.
Data sources (real, public, polled at runtime — no mocks)
| Source | URL pattern | Refresh | Notes |
| --- | --- | --- | --- |
| HackerOne public program directory | https://hackerone.com/programs/search?query=type%3Ahackerone&sort=published_at%3Adescending&page=N | nightly, 03:17 UTC | returns paginated JSON with name, url, stripped_policy, meta.submission_state |
| Bugcrowd public engagements | https://bugcrowd.com/engagements.json?category=bug_bounty&page=N | nightly, 03:42 UTC | returns paginated JSON with name, briefUrl, rewardSummary, accessStatus |
| HackerOne per-program detail | https://hackerone.com/{handle} | every 15 min, max 30/run, only detail_stale=1 rows | scrapes <meta og:description> to enrich policy text |
All requests send User-Agent: bounty-slop-watch/1.0 (+https://holyai.me/bounty-slop-watch) and respect a 1 req/s per-host rate limit. If a source fails the scrape run is logged to scrape_runs with the error; existing data is not wiped.
On first boot the server detects an empty DB and runs the two directory scrapes immediately (about 30 seconds total) before scheduling the nightly cron jobs.
Classifier
Pure keyword rules (deterministic, cheap, in classifier.js). Order of precedence:
program closed,discontinued the program,ended the program, … →closedprogram paused,not accepting reports,intake closed, … →paused- AI mention (e.g.
ai-generated,llm-generated,chatgpt,used ai) + a ban verb (prohibit,reject,ban,forbid,not accept) →ai_banned/ai_policy=banned - AI mention + a restrict verb (
must disclose,require human,limit) →ai_policy=restricted - Disappeared from directory for ≥2 consecutive runs →
closed+disappearedevent - Default →
active/ai_policy=allowed
Bugcrowd accessStatus and HackerOne submission_state override status when the platform itself says the program is paused/closed.
HTTP endpoints (all under /bounty-slop-watch)
| Method | Path | Returns |
| --- | --- | --- |
| GET | /health | {ok:true} |
| GET | / | SPA shell |
| GET | /program/:platform/:handle | SPA shell (deep-link) |
| GET | /badge/:platform/:handle.svg | SVG badge — color by status |
| GET | /feed.xml | RSS 2.0 of last 50 program events |
| GET | /feed.xml?program=hackerone/curl | RSS scoped to one program |
| GET | /api/summary | counts by status, total, last successful scrape |
| GET | /api/programs?status=&platform=&q=&limit=&offset= | filterable list |
| GET | /api/programs/healthiest?limit=20 | top active by bounty ceiling |
| GET | /api/casualties?days=30 | recent negative transitions |
| GET | /api/restrictions | programs with restricted/banned AI policy |
| GET | /api/program/:platform/:handle | full record + last 20 events |
| GET | /api/events?limit=50&kind= | raw event stream |
| GET | /api/scrape-runs?limit=20 | scraper transparency |
No POST/PUT/DELETE. No auth. CORS open on /api/* and badge so the SVG embeds cleanly.
Storage
SQLite (better-sqlite3, WAL) at data/bounty-slop-watch.db. Three tables:programs, program_events, scrape_runs. Schema lives in db.js.
Embeddable badge

Color: green=active, yellow=restricted, orange=paused, red=closed/ai_banned, gray=unknown.
Run locally
npm install
PORT=4877 node server.js
First boot kicks off the two directory scrapes and populates the DB in ~30 s. Then the cron schedule takes over (nightly).
What this product is not
- Not a place to file reports or host PoCs.
- Not an auth-gated dashboard. Everything is public.
- Not a substitute for reading the actual program policy — the classifier is keyword-based and approximate.