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.