320 findings, 4 submittable: inside a bug bounty campaign dashboard
320 raw findings, 4 submittable. How SecurityClaw tracks bug bounty campaigns at scale — dashboard architecture, submission rates, and triage layer.
Affiliate Disclosure: This site contains affiliate links. We earn a commission when you purchase through our links at no additional cost to you.
Most bug bounty coverage is about the clever finding. The CORS chain, the subdomain takeover, the exposed API key. What rarely gets covered is the unglamorous infrastructure behind running campaigns at scale: how do you track what you’ve tested, what you found, what’s still submittable, and what’s blocked?
After 21 campaigns across Intigriti, YesWeHack, and direct programs, the SecurityClaw team found themselves drowning in campaign directories. Findings scattered across JSON files and markdown reports, no quick way to answer basic questions.
So they built a dashboard.
The pipeline problem
Every SecurityClaw campaign produces a structured output directory:
campaign-results/
visma-20260507/
campaign_meta.json # target, timestamp, skill count
findings.json # structured findings with severities
TRIAGE_REPORT.md # human-readable analysis + submission decisions
skill_results.json # per-skill execution results
The pipeline runs through four stages: Found (raw automated output), Triaged (false positives filtered, submittable findings identified), Submitted (report sent to the platform), Resolved (triaged by the program, bounty paid or declined).
Different campaigns are at different stages simultaneously. Keeping track of which ones still have submittable findings sitting untouched was the first thing that slipped.
What the dashboard shows
Running python dashboard/report.py against the campaign results directory:
🔐 SecurityClaw Campaign Dashboard 2026-05-12 15:26 UTC
Campaigns: 21 (bug bounty: 15)
Raw findings: 320 by severity → H:101 M:121 L:54 I:75
Submittable: 4
Submitted: 1
Blocked: 3
Campaign Target Platform Date Type Skl Fnd Severity Sub
────────────────────────── ──────────────────── ────────── ───────── ────────── ─── ─── ──────────── ───
wolt-20260510 wolt.com (manual) 2026-05-10 submission 0 0 H:6 M:4 L:3 📋1
visma-20260507 aiassistant.visma… Intigriti 2026-05-07 bug_bounty 13 21 H:7 M:10 L:2 ⏳2
tomorrowland-20260507 cas.tomorrowland.com Intigriti 2026-05-07 bug_bounty 17 28 H:2 M:15 L:2 ⏳1
...
Pending submissions:
📋 wolt-20260510 — 1 submittable → Intigriti
📋 tomorrowland-20260507 — 1 submittable → Intigriti
📋 visma-20260507 — 2 submittable → Intigriti
320 raw findings across 21 campaigns. Only 4 submittable. That 1.25% rate is about what you’d expect from automated scanning once triage has run, but seeing the number in a terminal readout makes it more concrete than reading about false positive rates in documentation.
Architecture: zero external dependencies
The dashboard reads directly from the campaign-results directory structure. No database, no web server, no config file required.
from dashboard.parser import load_all_campaigns
from pathlib import Path
records = load_all_campaigns(Path("campaign-results"))
for r in records:
print(f"{r.name}: {r.raw_finding_count} findings, {r.submittable_count} submittable")
It pulls from two data sources per campaign:
findings.json— structured findings with severity labelsTRIAGE_REPORT.md— markdown triage with platform, submittable count, block reasons
The markdown path matters more than it sounds. Not all campaigns produce machine-readable output — research campaigns and manual submissions use markdown only. A dashboard that skips those gives you a misleading picture of where you actually stand.
What “blocked” means in practice
Three of the 21 campaigns are flagged blocked:
| Campaign | Target | Platform | Block reason |
|---|---|---|---|
| contentsquare | contentsquare.com | YesWeHack | DataDome — 403 with x-datadome: protected |
| outscale | outscale.com | YesWeHack | Akamai IP-level block, no UA bypass possible |
| telenor-se | telenor.se | YesWeHack | CDN-level block |
Blocked campaigns are useful data, not dead weight. Knowing that DataDome and Akamai block automated scanning from datacenter IPs means the next time you see those services in scope, you plan around them from the start — residential proxies, browser-based tooling, or manual testing. Without the dashboard surfacing them, they’d just sit in a directory and get re-attempted.
The submission rate question
320 raw findings, 4 submittable, 1 submitted. End-to-end that’s 0.3%.
The campaigns use automated skills to surface candidates, not to guarantee valid bug reports. Triage filters false positives before human effort or submission fees get spent. The 99.7% that don’t make it through are mostly missing security headers (real findings, usually below submission threshold), false positives from redirects and CDN-mangled responses, and informational recon observations — certificate transparency data, tech stack exposure, path enumeration.
The findings that do survive triage tend to be CORS misconfigurations, subdomain takeovers, and hardcoded secrets. These are deterministic: the misconfiguration is either present or it isn’t.
The CVSS distribution in the raw findings is H:101, M:121, L:54, I:75. A lot of those High labels are SecurityClaw’s own severity assignments from the skill output. Human triage still needs to confirm exploitability in context — a CORS finding drops from High to Informational if the target’s program explicitly excludes unauthenticated CORS.
What the submittable findings actually were
The 4 submittable findings across 21 campaigns give a concrete picture of what automated recon surfaces in real programs:
Wolt (wolt.com / Intigriti): CORS wildcard subdomain reflection with Access-Control-Allow-Credentials: true, chained with 5 dangling Route53 NS delegations. The chain is what made it submittable as HIGH: subdomain takeover via Route53 zone squatting → CORS bypass → credentialed cross-origin read of the main wolt.com API. Each piece individually was MEDIUM at best. The chain elevates it to HIGH.
Verification at 2026-05-10T07:30Z:
curl -sv -X OPTIONS \
-H "Origin: https://evil.wolt.com" \
-H "Access-Control-Request-Method: GET" \
"https://wolt.com" 2>&1 | grep "access-control"
# access-control-allow-origin: https://evil.wolt.com
# access-control-allow-credentials: true
Visma (aiassistant.stage.vismaonline.com / Intigriti): Two clickjacking findings. First: aiassistant.stage.vismaonline.com missing both X-Frame-Options and Content-Security-Policy: frame-ancestors. Second: autointerface.stag.visma.net serving X-Frame-Options: ALLOWALL — an invalid directive that Chrome, Firefox, and Safari silently ignore, leaving the page fully frameable. The ALLOWALL value is a known false-safety trap: developers who add it believe they’ve protected against clickjacking, but all modern browsers treat unrecognised X-Frame-Options values the same as no header at all.
Tomorrowland (cas.tomorrowland.com / Intigriti): Clickjacking on the CAS Single Sign-On portal. The SSO authentication page was fully embeddable with no framing protection. An attacker could iframe the login form inside a fake ticket-giveaway page and use UI redressing to steal credentials. Rated MEDIUM — CVSS 4.3 — because the SSO portal handles authentication for all Tomorrowland services including ticket purchase and payment methods.
HTML export
For team review or program retrospectives:
python dashboard/report.py --html campaign-dashboard.html
The output is a self-contained HTML file — dark-themed, colour-coded by severity, no external dependencies. Useful for sharing context with program managers or writing up a retrospective without needing a live server.
The triage layer: where the real work happens
The gap between 320 raw findings and 4 submittable ones isn’t a failure of the scanner — it’s the triage layer working correctly. Understanding what gets filtered and why is what separates experienced bug bounty hunters from the ones who burn submission credits on invalid reports.
Common false positive patterns SecurityClaw triage catches:
-
CSP report-only mode — Doctolib’s
api.doctolib.frserves a well-craftedContent-Security-Policy-Report-Onlyheader with nonces and a strict allowlist. SecurityClaw’s header checker correctly flags the absence of an enforced CSP, but triage catches that report-only is a mid-rollout state, not a missing control. Submitting “no CSP” on a target that has a report-only CSP is a sure way to get marked as informational. -
Permissions-Policy and COOP/CORP — these are valid security controls, but on API endpoints they have negligible exploit paths. Programs frequently treat them as informational or out-of-scope. Triage catches the ones where there’s no demonstrated impact path.
-
SRI missing on vendor CDN scripts —
Subresource Integritymissing on Datadog RUM or Sentry scripts is a real finding in theory, but programs almost universally consider third-party monitoring scripts out-of-scope for SRI enforcement. Triage flags these as “informational — vendor dependency, not submittable.” -
WAF false-positive detection — Tomorrowland’s scanner returned “Fastly MEDIUM confidence.” Actual response headers showed CloudFront (
via: 1.1 ...cloudfront.net,x-amz-cf-pop: DUB56-P4). The scanner’s WAF fingerprinting matched on a Fastly CDN signature pattern that appears in some CloudFront responses. Triage caught the discrepancy by checking the actual response headers.
The 0.3% end-to-end submission rate looks like scanner failure. It isn’t. Automated scanning is a surface-coverage tool. Human triage is the quality gate. The dashboard makes the pipeline visible so neither step gets skipped.
Where this goes next
Current planned additions:
- Payout tracking — link submitted findings to bounty amounts once resolved
- CVE correlation — surface campaigns with findings linked to known CVEs (connects to the June 2026 CVE opportunity analysis)
- Platform comparison — Intigriti vs YesWeHack: where does SecurityClaw find higher-quality submittable findings?
For a closer look at the campaigns where WAF blocks prevented automated scanning entirely, see How SecurityClaw Got Past bol.com’s WAF.
The source is in SecurityClaw/dashboard/. If you’re building something similar, the structured campaign output format is the part worth copying — the dashboard is just a query layer over consistently organised files.
The numbers that matter
Running 21 campaigns across multiple bug bounty platforms produces a lot of data that doesn’t mean much without context. Here are the numbers that actually tell you how SecurityClaw is performing:
- 4 minutes 8 seconds — median campaign run time on a single
t3.mediumEC2 instance, 16 skills, a real European target - 1.25% submission rate — raw findings to submittable after triage. Consistent with industry benchmarks for automated scanning.
- 0.3% end-to-end rate — raw findings to actually submitted. The gap between 1.25% and 0.3% is submission backlog, not additional triage filtering — those reports are sitting ready.
- 3 blocked campaigns — 14% of bug bounty campaigns hit a WAF or bot protection layer that prevented automated scanning. Without the dashboard, those would be invisible.
- H:101 / M:121 in raw findings — these are scanner-assigned severities, not confirmed exploitability. Human triage downgrades the majority. The H count is the most inflated — scanners tend to call missing CSP
HIGH, which overstates the actual risk in most contexts.
The dashboard’s value isn’t the chart output. It’s that every campaign is accounted for, every blocked target is visible, and nothing submittable sits in a directory unnoticed.
Building your own campaign infrastructure? The skills come before the automation. Hack The Box teaches the manual techniques SecurityClaw automates — understanding why a finding is exploitable before writing a skill to detect it at scale matters. TryHackMe covers the web security fundamentals if you’re starting out. For campaigns scanning residential-range IPs (bypassing the datacenter IP blocks that trip Cloudflare bot detection), a residential VPN like NordVPN gives you the IP diversity automated scanners need.
Peng is Senior Security Engineer at ClawWorks, the team behind SecurityClaw and bughuntertools.com.