A primary goal of a bug bounty program is to fix bugs that impact an app’s security, especially since these are bugs that have made their way into production. While it’s commendable to strive for zero bugs in production, it’s an over-simplification to tie the success of a program to such binary terms as whether a bug is found or not.
A more nuanced approach would be to track how well vulns are resolved and whether entire classes of vulns can be mitigated. For example, are the same ones being rediscovered, are they being discovered in old or new code, is their impact diminishing in any way? Add in a time scale: how long does it take to fix a vuln?
It’s very likely that cross-site scripting (XSS) will be the most reported vuln class for a web app. XSS lurks everywhere, in apps large and small, in apps with dedicated security teams and those without. Its prevalence is a testament to the unsolved security challenge of mingling user-supplied data with raw HTML.
This mixing of content with context appears in many other types of web vulns. Developers tackled SQL injection by creating prepared statements (aka parameterized queries) that strictly separate the semantics of a SQL query from its syntax. This technique stops user-supplied data from modifying a query even if that data contains SQL syntax or keywords like single or double quotes, semicolons, and Boolean operators. Programmers have had access to prepared statement APIs for over a decade. This straightforward programming pattern should have made SQL injection obsolete in modern web apps. Instead, we still see developers re-introducing this vuln through a different type of API — advanced persistent ignorance.
You can also think of XSS as an HTML injection vuln. Developers have created templating engines, parsers, and encoding routines to make introducing XSS more difficult. These techniques aim to make secure programming the default behavior and to make insecure code stand out as anomalous. But they’re neither as universal nor as error-free as prepared statements.
Vuln Reduction Tactics
So what happens after you’ve confirmed an XSS report is valid? The following paths are a few of many possibilities (for example, we’ll skip the perilous maze of “accepting the risk” for now).
Recreate — Can your QA infrastructure automatically reproduce the vuln? Sometimes this is as easy as generating a test case with a specific query string value. In other situations it may require the ability to set up a particular state in the app, or render HTML within a browser. Having a flexible QA environment that can handle security issues is a key towards catching vulns early. Adding new tests based on bug bounty reports should be a habit.
Research — Look for similar programming mistakes throughout the app’s code. Are you doing this manually? It’s a great opportunity for automation, even if it’s a simple pattern to catch regressions for one vuln. In our XSS example, these scans might include whether a template function was present, or what output encoding was applied.
Refactor — Can the code be smarter? Or even smaller? It’s a lot easier to consolidate calls to a few security functions than cut-and-paste the same secure code multiple times.
Remove — Should the affected code even be there? Does anyone own it or even understand it? If it can’t be removed, why? Obtaining feedback about why code can’t be removed can highlight additional risks to the application. You may not be able to address those risks, but it’s better to know they exist.
Reduce — Is there something that can reduce risk (or, alternately stated, elevate the baseline security) of the app? With XSS, one solution could be deploying Content Security Policy (CSP) headers. CSP doesn’t fix the underlying vuln, but it does inoculate an app against certain exploits. This can give breathing room to developers.
Such activities contribute to resolving vulns more effectively, but they require changing code and they require time. Measuring that effort gives better insight into what bug bounty reports are telling you about your app. If you’re getting dozens of vulns in legacy code, but you’re able to deploy good fixes in a matter of hours, that’s likely a positive indicator for your security development lifecycle. Conversely, if fixing new code causes cascading problems or requires significant time, then the app may be more brittle than you thought.
A Process of Exhaustion
It’s easy to mistake the popularity of XSS with impact or importance. Most XSS vulns require little expertise to discover, with dead-simple payloads like <script>alert(9)</script> and <img/src=x onerror=alert(9)>. Their effect is starkly evident — a pop-up window in the browser — but their impact to security is often low risk. Even so, the strategies you employ to minimize the class of XSS vulns should inform approaches to hardening session management, authorization, and authentication mechanisms as well.
Bug bounties are a haphazard approach to app security that only highlight vulns at the end of a security development lifecycle. Use them as a feedback mechanism to improve security in earlier phases. A bug bounty is good at revealing flaws, but it’s poor at confirming an app’s strengths. That’s the kind of exercise and coverage that comes from vulnerability assessments and penetration tests.
Be careful about getting caught up in managing pure quantities of vulns or only focusing on reaching zero vulns. Tamping down a dozen XSS vulns isn’t the same as fixing one authentication bypass or a vuln that leaks sensitive user data. Resist the temptation to assign priority solely based on the category of vuln. Conduct threat modeling exercises and guide developers through informed discussions about impact to improve their security awareness. Education is more sustainable than mindlessly stating “XSS bad, HTTPS good” without explaining their basic concepts.
Consider bug bounty reports as an indicator species for your app’s flaws. A thriving population of bugs exposes the need to address systemic issues. If you repeatedly encounter the same type of bug, especially the exact same one, that may mean your developers are missing important feedback or neglecting to properly deploy solutions. Measure how you reduce bugs, both by process and by time. Then use those processes to build software that’s resilient to whole classes of bugs.