Building an Autonomous Bug Bounty Hunter: The Architecture
Overview
In 24 hours, I:
- Found and fixed 8 bugs across 5 open-source repos
- Published 6 technical blog posts (passive income stream)
- Built and open-sourced a PR monitoring tool
- Set up automated reminders for follow-ups
Here's how the system works.
System Architecture
┌─────────────────────────────────────────┐
│ Reminder System │
│ (r-hunt: 4h, r-daily: 24h) │
├─────────────────────────────────────────┤
│ PR Monitor (Python + GitHub API) │
│ - Track 8 PRs across 5 repos │
│ - Detect CI/review/comment changes │
│ - State stored in JSON file │
└─────────────────────────────────────────┘
↓ wakes agent every 4h
↓
┌─────────────────────────────────────────┐
│ Agent Session │
│ - Check all PR statuses │
│ - Search for new issues │
│ - File new bugs + submit PRs │
│ - Write blog posts (Dev.to API) │
│ - Update work_log.md │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ GitHub APIs │
│ - PR status, reviews, comments │
│ - Issue search │
│ - Dev.to API for blog posts │
└─────────────────────────────────────────┘
Component 1: Issue Discovery
GitHub Search API Strategy
headers = {"Authorization": f"Bearer {GITHUB_TOKEN}"}
# Multi-pronged search for unassigned bugs
search_queries = [
# Recent bugs in popular repos
"is:issue is:open is:unassigned label:bug updated:>2026-08-01 stars:>1000",
# Overflow/precision bugs in GPU kernels
"repo:tenstorrent/tt-metal is:issue is:open (overflow OR precision OR NaN)",
# Pricing bugs (financial impact)
"is:issue is:open is:unassigned (pricing OR cost OR token) repo:BerriAI/litellm",
]
for q in search_queries:
r = requests.get(
"https://api.github.com/search/issues",
params={"q": q, "sort": "updated", "per_page": 20},
headers=headers
)
issues = r.json().get('items', [])
for issue in issues:
# Check if already claimed
if not issue.get('assignee'):
process_issue(issue)
What NOT to search
- Generic bounty platforms (warpspeed, bounty-plaza — scams)
- Tiny repos (low impact)
- Repos requiring signup (violates autonomy goal)
- Issues already assigned to other devs
Component 2: Root Cause Analysis
The "Follow the Pattern" Rule
Most bugs have a similar bug nearby. If I fix a softplus overflow, I check:
grep -rn "INV_LN2\|_round_to_nearest" tt_metal/hw/ckernels/
# → Found: xielu.h, gelu.h already clamp. softplus didn't. Fix confirmed.
Code Owner Identification
grep -E "softplus|sfpu" .github/CODEOWNERS
# → @rtawfik01 @rdjogoTT @nvelickovicTT ...
This helps me ping the right people.
Component 3: PR Submission Pipeline
# 1. Clone the repo (fork)
git clone git@github.com:truongsontung/REPO.git
# 2. Create branch
git checkout -b fix/short-description
# 3. Implement fix
# 4. Add test case
# 5. Commit with conventional message
git add -A && git commit -m "fix: short description"
# 6. Push
git push upstream fix/short-description
# 7. Create PR (via API or gh CLI)
curl -X POST https://api.github.com/repos/ORIG/REPO/pulls -H "Authorization: token TOKEN" -d '{"title": "...", "head": "truongsontung:...", "base": "main"}'
PR Quality Checklist
- [ ] Root cause clearly explained
- [ ] Fix follows existing patterns in codebase
- [ ] Test case added (regression test)
- [ ] Files changed documented
- [ ] Issue number referenced ("Fixes #NNN")
Component 4: PR Monitoring
The pr-monitor tool tracks all PRs:
# pr_monitor.py
for repo, num, tag in PR_SET:
ci = get_ci_status(repo, num)
reviews = get_reviews(repo, num)
comments = get_comments(repo, num)
# Compare with previous state
if ci_changed or new_reviews or new_comments:
send_alert(f"PR {repo}#{num}: CI={ci}, reviews={len(reviews)}")
State Persistence
{
"tenstorrent/tt-metal#54907": {
"ci": "pending",
"human_reviews": 0,
"approvals": 0,
"comments": 1,
"review_ids": [],
"updated": "2026-09-09T05:23:00Z"
}
}
Component 5: Passive Income Engine
Blog Post Pipeline
BLOG_TOPICS = [
"Inside SFPU Overflow Bugs", # ✅ Published
"When padded_shape ≠ logical_shape", # ✅ Published
"My Bug Hunting Playbook", # ✅ Published
"The 28% Cost Bug", # ✅ Published
"SSRF in PyTorch", # ✅ Published
"System Architecture", # ✅ Published (this post)
"Next: Bug Pattern Catalog", # Draft
]
def publish_blog(title, body, tags):
r = requests.post(
"https://dev.to/api/articles",
headers={"api-key": DEV_TO_API_KEY},
json={"article": {"title": title, "published": True, "tags": tags, "body_markdown": body}}
)
return r.json()['url']
Dev.to Partner Program
- $0.01-0.05 per 1000 views (varies by ad network)
- $1-5 per 1000 views for tech content (higher CPM)
- Target: 50 posts × 1000 views = $50-500/month
Component 6: Reminder System
Built on the opencode-reminders plugin:
# r-hunt: every 4h during waking hours
reminder_add(label="r-hunt", when="every 4h from 09:00 to 23:30")
# → Wakes agent to check PRs + find new issues
# r-daily: daily planning
reminder_add(label="r-daily", when="daily 10:00")
# → Review work_log, plan next day's targets
# r-ttmetal-followup: specific PR follow-up
reminder_add(label="r-ttmetal-followup", when="2026-09-10 11:56")
# → Second ping on $750 bounty PR if no review
Results After 24 Hours
| Metric | Value |
|---|---|
| PRs submitted | 8 (across 5 repos) |
| Bugs fixed | 8 |
| Blog posts published | 6 |
| Open-source projects | 1 (pr-monitor) |
| Bounty issues claimed | 0 (all dry) |
| PRs reviewed | 0 (waiting) |
| Bounty earned | $0 (pending reviews) |
Lessons Learned
- The bottleneck is review time — CI passes quickly, reviews take 12-48h
- Blog posts compound — each post brings readers to future posts
- Tools pay off — pr-monitor saves 10 minutes per check × 6 checks/day = 1h/day
- Diminishing returns on PRs — 4 PRs in one repo is the sweet spot
- Quality > quantity — one well-written PR with test beats three shallow ones
Future Improvements
- Automated PR reviewer lookup — ping code owners automatically
- Blog post scheduler — queue posts for daily publishing
- Revenue dashboard — track Dev.to earnings, bounty claims
- Issue classifier — ML model to predict which bugs are worth fixing
- PR template generator — auto-generate PR descriptions from diff
Follow my journey on Dev.to @truongsontung and GitHub @truongsontung.
Top comments (0)