Skip to content
TRIAGERS™
Deep Dives · 7 min read · TRIAGERS™ Team

Duplicate Bug Bounty Reports: Why Dedup Is Harder Than It Looks

Why duplicates dominate bug bounty noise, why naive dedup fails, how root-cause dedup works, and how to deliver a dupe verdict without a flame war.

Ask anyone who runs a bug bounty program what fills their queue and you'll get the same answer: duplicates. On a mature public program it's entirely normal for duplicates to outnumber novel valid findings several times over. For popular, easily-scanned bug classes like subdomain takeover or exposed .git directories, the ratio gets silly.

This is structural, not a sign your program is broken. Hundreds of researchers are pointed at the same attack surface with the same tooling, the same wordlists, and the same Twitter feed telling them what's hot this month. When a new nuclei template drops, every program on the internet receives the same finding forty times in a week.

Handling duplicates badly is expensive in both directions: mark a novel bug as a dupe and you've stolen a bounty and made an enemy; mark a dupe as novel and you've paid twice and shipped two tickets for one fix.

Why naive dedup fails

Most dedup, in practice, is a triager searching old reports for a matching URL. That fails in both directions, because "is this the same bug?" is actually three different questions wearing one trenchcoat:

Same endpoint ≠ same bug

POST /api/orders can host an IDOR in the order_id parameter and a race condition in coupon redemption. Same endpoint, unrelated bugs, different fixes. Endpoint-matching dedup closes the second report incorrectly, and the researcher (who is right) escalates to the platform, publicly, with receipts.

Same class ≠ same bug

Two stored XSS reports are not duplicates of each other just because they're both stored XSS. One is in the profile bio rendered on the public page, the other in the filename of an uploaded attachment rendered in the admin panel. Different sinks, different sanitisation gaps, different fixes. "We already have an XSS report open" is not a dedup argument; it's an admission you're not reading them.

Different endpoints CAN be the same bug

This is the direction that costs programs money. A missing tenant check in shared middleware manifests as "IDOR on /invoices", "IDOR on /projects", and "IDOR on /webhooks": three reports, three endpoints, one line of broken code. If you treat them as three novel findings you pay three bounties for one fix, and your vulnerability metrics tell you a story about three bugs that never existed.

Dedup on root cause

The only dedup axis that holds up is the root cause: which broken assumption in which piece of code produces this behaviour? Two reports are duplicates if and only if fixing one necessarily fixes the other.

That definition does real work:

  • IDOR on /invoices and IDOR on /projects, both via the same unscoped middleware → one fix kills both → duplicates (of each other, or of whichever landed first).
  • Reflected XSS in ?q= and reflected XSS in ?ref= on the same page, both flowing through the same unescaped template variable → duplicates.
  • Reflected XSS in ?q= escaping HTML but not attribute context, vs stored XSS in profile bio → same class, same app, unrelated root causes → not duplicates.

The catch: root-cause dedup requires actually understanding the bug, which means the dedup decision can't fully precede reproduction. In our triage workflow dedup starts before reproduction (search by endpoint and parameter to find candidates), but the verdict waits until you understand the mechanism well enough to say whether one fix covers both reports. A dupe verdict is a technical claim. Treat it like one.

It also requires institutional memory. A triager who wasn't around for the original report six months ago can't recognise its cousin today unless the original was written up with the root cause named. This is one of the quiet arguments for triage continuity: rotating a different engineer through triage duty every sprint means nobody ever accumulates the memory that makes dedup accurate. It's a big part of the in-house vs outsourced calculus.

Delivering a dupe verdict without starting a war

From the researcher's side, "duplicate" is the worst possible outcome. "Not applicable" means they were wrong. Fine, it happens. "Duplicate" means they were right and get nothing. Every researcher has a story about a suspicious dupe verdict, and some of those stories are true, because some programs have absolutely used "duplicate" as a bounty-avoidance mechanism. You inherit that trust deficit whether you deserve it or not.

So a dupe verdict needs to carry evidence:

  1. Reference the original concretely. Report ID and original submission date at minimum. "This was previously reported" with no identifier reads as "trust us," and nobody does.
  2. Name the shared root cause. "Duplicate of #1204 (reported 2026-01-18): both findings stem from the missing tenant scope in the shared authorization middleware; the fix for #1204 resolves this endpoint as well." That's checkable reasoning, not a verdict from the void.
  3. Tell them the state of the fix. If the original is still unfixed, say so. Researchers are considerably calmer about dupes when it's clear the bug is genuinely known and tracked rather than being memory-holed.
  4. Never miss the non-dupe part. If their report is 80% dupe and 20% novel escalation (the known IDOR, but they showed it also leaks password hashes), the novel part is a finding. Splitting that out and rewarding it is how you keep good researchers. Missing it is how you end up in a public dispute you'll lose.

Tone matters as much as content. The researcher did real work and found a real bug. "Thanks. This is valid, but it duplicates #1204" lands very differently from a templated closure, and it costs you one sentence.

When a duplicate deserves money anyway

Strict platform rules say dupes get nothing. Strict application of that rule is sometimes the wrong call:

  • The dupe adds material new information. A stronger exploitation path, a bypass of the attempted fix, proof the impact is worse than the original claimed. That's not a duplicate of the finding. It's an escalation of it, and escalations are findable work.
  • The original has been sitting unfixed past your own SLA. If a bug has been open for eight months and a second researcher finds it independently, the dupe is a free re-test proving your exposure window is real. Some programs pay partial bounties on dupes of long-unfixed issues precisely to keep that signal flowing, and because the alternative message is "we knew, we didn't fix it, and you get nothing," which is a rough look. Your SLA metrics should be flagging these before researchers do.
  • The race was genuinely close. Two reports on the same novel issue hours apart, before anything was triaged. Rules say first wins. A partial for the second costs little and buys a lot of goodwill on a program that wants repeat visitors.

None of this obligates you to pay every dupe: that just incentivises spray-and-pray resubmission. The principle is narrower: pay for new information or demonstrated program failure, not for repetition.

The dedup flow we actually run

Compressed to a checklist:

  1. Search prior reports by endpoint, parameter, and vulnerability class. Collect candidates, don't conclude.
  2. Reproduce enough to identify the root cause, not just the symptom.
  3. Ask: does fixing the candidate original necessarily fix this? Yes → dupe. No → novel, whatever the URLs look like.
  4. Check for novel deltas in the "dupe": new impact, fix bypass, escalation. Split and reward if present.
  5. Communicate with report ID, root-cause reasoning, and fix status.
  6. Link the reports in your tracker so the fix verification covers both.

It's more work per report than string-matching URLs. It's also the difference between dedup as a defensible technical judgement and dedup as a coin-flip that occasionally detonates on social media.


Dedup accuracy comes from reps and memory: triagers who've seen tens of thousands of reports recognise a root cause on sight. TRIAGERS™ provides on-demand triage teams who bring that memory to your program from day one. If your queue is mostly déjà vu, get in touch.

Keep reading
The Triage Brief

New articles, straight to your inbox.

Practical triage writing, published a few times a month. Unsubscribe anytime.

Or grab the RSS feed.

Drowning in unread reports?

Lease an expert triage team that validates, reproduces and rates every submission, so your engineers only see signal.

Get a triage team