Share
## https://sploitus.com/exploit?id=8E8DEDB8-F75A-5B6C-8318-C741B59E1CE6
# BountySkiller โ hacktivity & writeup collector
Flask app that pulls disclosed HackerOne hacktivity or bug bounty writeups from the
last X months and writes them to JSON under `data/`.
```
pip install -r requirements.txt
python app.py # http://127.0.0.1:5000
```
## Sources (dropdown)
| id | what | notes |
|---|---|---|
| `all` | every source | failing sources are skipped, errors reported per source |
| `hackerone` | HackerOne Hacktivity | live GraphQL, no auth. Program filter + free-text query. Index caps deep paging at 10k rows |
| `pentesterland` | Pentester.land writeups archive | 6.4k curated writeups, but upstream stopped updating 2024-09-18 |
| `medium` | Medium tags: bug-bounty, bug-bounty-writeup, bugbounty, bug-bounty-tips | RSS exposes only ~10 newest per tag |
| `infosecwriteups` | InfoSec Write-ups | RSS, ~10 newest |
| `portswigger` | PortSwigger Research | RSS, ~40 newest |
| `intigriti` | Intigriti blog | RSS |
| `research_blogs` | Project Zero, Assetnote, Datadog Security Labs, samcurry.net | RSS/Atom |
| `google` | Google Programmable Search | needs API keys, max 100 results/query |
Google needs credentials โ free tier is 100 queries/day:
```
export GOOGLE_API_KEY=... # https://developers.google.com/custom-search/v1/introduction
export GOOGLE_CSE_ID=... # https://programmablesearchengine.google.com/
```
Or pass `google_api_key` / `google_cse_id` as query params.
## API
- `POST /api/fetch?source=all&months=6&program=nodejs&query=IDOR&min_bounty=500` โ start job
- `GET /api/sources` โ dropdown contents
- `GET /api/status` โ progress, per-source counts, per-source errors
- `GET /api/reports` โ newest result set
- `GET /api/files`, `GET /data/` โ download
## Output schema
```json
{
"generated_at": "...", "source": "all", "months": 6, "cutoff": "...",
"count": 483, "per_source": {"hackerone": 379, "medium": 38},
"source_errors": {"google": "..."},
"items": [{
"source": "hackerone", "kind": "report",
"title": "...", "url": "...", "published_at": "...",
"author": "...", "program": "nodejs", "severity": "High",
"bounty": 1337, "tags": ["Path Traversal", "CVE-2025-24293"],
"extra": {"report_id": "...", "substate": "resolved", "votes": 11}
}]
}
```
Items are de-duped by URL across sources and sorted newest-first.
## Gotchas
- HackerOne index field is `team_handle`, not `team.handle` โ the latter silently returns 0 hits.
- RSS sources only expose recent posts, so `months=24` returns the same rows as `months=1` for them.
- `bounty` is often `null` โ HackerOne only exposes amounts programs chose to disclose. `min_bounty` drops null-bounty rows.
- Requests are rate-limited (0.4s between HackerOne pages). Don't hammer.