Introduction to Bug Bounty Duplicates

A duplicate (in the bug bounty world), is a report for an issue that was previously known or identified. However, when determining whether or not a given finding is truly a duplicate, the solution isn’t always cut and dried. Many situations require a non-trivial amount of nuance and context. To help with duplicate evaluation in these cases, we’ve put together a guide for a few common duplicate scenarios, where we explain how Bugcrowd looks at these situations, and how we recommend clients approach them as well. As we go through these scenarios, there are three key principles to keep in mind:

  • Touch the code (or make a change), pay the bug
      • If a finding causes you to make a change—and is in scope + is a vuln that’s rewarded as part of the program brief—it should be rewarded.
  • Similar != same
      • If a finding is similar to another finding, but requires a separate change, it is a unique issue that needs to be rewarded independently.
  • Many != systemic
    • Just because there are many of a particular vulnerability type, that doesn’t mean they’re all part of the same root issue.

The importance of context and nuance in duplicate evaluation

As a quick note, when triaging findings, Bugcrowd’s engineered triage takes all of the above into account (to the best of our abilities—as there are extenuating circumstances in some cases that we don’t have visibility into). We leverage our ML-powered de-duplicate detection, contextual intelligence from over a decade’s worth of data on vulnerabilities, and human validation to perform a thorough review of any and all findings that come into the platform to ensure (1) duplicates are properly identified; and (2) all unique issues are elevated for review by the client. 

Scenario #1: Multiple SQLi Vulnerabilities

  • A researcher has identified ten SQLi vulnerabilities across your application for a number of different queries and resources. Since they are all SQLi, you decide to pay for one finding and mark the others as duplicates.

This approach is misguided because multiple vulnerabilities of the same vulnerability class does not equal them all being the same vulnerability. Seeing a large amount of the same vulnerability class reported on a single asset is fairly common—when there are one or two of a vulnerability type, there are usually a lot more. This may be due to the same developers making the same mistake(s) in different places across the attack surface. Like birds, vulns of a feather commonly flock together. 

Assessing Vulnerability Clusters and Determining True Duplicates

In situations like this, it’s important to realize that even though there are many of the same type of vulnerability, they’re sprinkled across the application in different contexts. This means that it’s highly unlikely that they’re all one fix. 

Some of them might be true duplicates. If fixing one removes the need to fix another, refer back to principle #1 from above, “touch the code / make a change, pay the bug.” If, as a result of fixing a vulnerability, one no longer needs to touch the code or make a change to fix another finding, then the latter is truly a duplicate of the former. 

Ensuring Fair Recognition and Reward for Unique Findings

However, it’s imperative that we only mark something a duplicate if it’s truly a duplicate (e.g. fixing the parent finding removes the need to fix the duplicate finding). In the case of having ten SQLi scattered across the application, if we try to reward only one finding and dupe the rest, that’s tantamount to saying that only one change to one area of the codebase was made as a result of those issues. If we look at the situation honestly, had the researcher only reported one of the ten SQLi issues, and that issue got fixed, there would likely still be at least nine other vulnerabilities floating around even after the first one was remediated—because each requires a unique fix. It may be tempting to assert that they’re all one-in-the-same, but that is very rarely the case.

THINGS TO KEEP IN MIND

In some cases, some might assert that implementing a WAF (or WAF rule) could count as a single “fix.” For instance, one could implement a WAF rule that blocks any injection of double quotes that were otherwise required for the SQLi vulnerability. In doing so, all the SQLi issues are no longer exploited, and are thereby “remediated.” However, from Bugcrowd’s view, findings need to be rewarded from the perspective of how they would be remediated in the underlying codebase, and not at the WAF layer. Adding a WAF rule or similar blocking mechanism is a half-measure that will invariably have a hole of its own at some point in the future that will leave the still-vulnerable application underneath exposed. There’s no shortage of WAF bypasses or other creative mechanisms that researchers have found to get around these controls, and as such, (1) any remediation should always start at the application layer; and (2) rewards should be administered based on fixes to the codebase, and not the WAF.

Scenario #2: Reflected XSS Vulnerabilities with Common Parameters

  • A researcher identifies 15 reflected cross site scripting (XSS) vulnerabilities across a number of pages on your application—however, they usually end in one of three parameters “page=”, “id=”, and “utm=”. Since they are all on unique pages (e.g. /view, /news, etc), and we previously talked about how it’s important to pay for all unique issues, you decide to pay for each finding independently.

This is partially correct, and partially incorrect. It is correct in that we want and need to reward for all the unique findings, given that these issues appear to be originating from three unique parameters. The most common outcome here is that there would be three unique findings (one for each vulnerable parameter), and the rest would be marked as duplicates of the initial issue for each parameter. 

Understanding Duplicates in Multi-Parameter Vulnerability Scenarios

But this is not always the case. Sometimes the same parameter name may be handled differently by different pages—this can be evaluated by looking at where the injection is reflected back on the page, and if it’s the same place for each parameter on each page. If that’s the case, they’re likely the same issue / underlying function applied on the different pages—despite appearing on unique urls. In cases like this, fixing the underlying function will remediate the issue on every page where that function is called, and so Bugcrowd will automatically mark each initial finding as unique per parameter, and then mark all subsequent ones for those parameters as duplicates. 

THINGS TO KEEP IN MIND

It’s worth noting that in a good number of cases, even multiple parameters will be duplicates of the other parameters across the same or multiple pages if they’re fundamentally part of the same issue. A good example of this is when the page url is printed in the page content. In such cases, the url could have 30 parameters, or even a fake parameter added to it would all be reflected back in the page via the same function on the backend—which again would only take a single fix to remediate, and thereby only be eligible for a single reward across all the parameters and pages that have this issue.

In doing so, we’re adhering to the principles outlined earlier: paying for all the places where the code is being changed (once per underlying function that will be fixed per parameter), and also keeping in mind that “similar != same.”

Scenario #3: CSRF Findings on Multiple Pages/Endpoints

  • A researcher submits 50 cross site request forgery (CSRF / XSRF) findings against the application for every available page/endpoint, since there is no anti-CSRF token present anywhere on the app. Since they’ve identified 50 points where there’s an issue, should they be paid out for 50 findings? 

This is where our third principle of duplicates comes into play: many != systemic. As we saw in the first and second example, many issues of a vulnerability class doesn’t mean that it’s automatically systemic, or that it should be condensed to a single finding. With certain bug classes though, it is possible to have systemic issues—CSRF being a notable example.

Clarifying Systemic Vulnerabilities and Their Influence on Payouts

If the application had anti-CSRF protections in 45 of the 50 places, and was just missing it in five of them, then each instance of missing CSRF protection would be a unique finding. This is because the protection exists, it just didn’t on those specific endpoints. However, since in our example there was no anti-CSRF anywhere on the application, it’s possible that once they turn it on (especially in modern frameworks), it’ll automatically apply itself to all of the pages/endpoints for the application, and resolve the many with a single code change. Now, this isn’t always the case, but very commonly is (specifically with CSRF). In such situations, we’ll label the issue as “systemic,” reward the first report, and mark all subsequent reports as duplicates. 

THINGS TO KEEP IN MIND

After the mitigation is applied, if there are places where the systemic fix doesn’t cover all the bases, then those would be net-new unique vulnerabilities that should be rewarded independently.

Other examples of systemic issues include subdomains that are load balanced or resolve to the same host. This is where reporting an issue on one will make it immediately applicable to all other subdomains that share the same codebase or host, etc. This isn’t an exhaustive list—just a couple examples of how/where vulnerabilities can be systemic.

Navigating Duplicates with Confidence

Hopefully this guide provides some context around how, when, and why duplicates are duplicates. It’s important to remember that in all cases relating to duplicates, it’s critical to interrogate and evaluate the situation, as context matters significantly. Many times it requires reviewing the codebase to see how many fixes a given bug will take to remediate. So, remember the three principles mentioned earlier:

  1. Touch the code (or make a change), pay the bug
  2. Similar != same
  3. Many != systemic

As long as you’re taking these principles to heart in each situation, it’s unlikely that you’ll get it wrong. If you have any questions, the Bugcrowd team is always here to help and provide advice. 

Finally, if nothing else, always remember, whether it’s updating documentation or the codebase—“touch the code or make a change, pay the bug”. 

Good luck and happy hunting!