Skip to content
Cybersecurity

The pitfalls of custom filters: an XSS injection and filter bypass case study

In this case study, our experts present how to bypass custom filters with simple filter evasion in order to perform an XSS injection.

Partager sur

The use of custom filters to protect an application against XSS injection is considered a bad practice, although it remains common. Such filters are generally insufficient to prevent malicious user inputs from compromising the security of the application.

The following case study describes a “simple” filter encountered during a penetration test, along with the reasoning required to bypass this filter and exploit the reflected cross-site scripting (XSS).

Before diving into the details of the encountered filter and the bypass solutions, we encourage testing this reflected XSS through downloading this HTML file:

The username parameter in the URL serves as the injection point for testing payloads.

The demonstration of XSS injection relies on the code provided in the previous section.

As with all reflected XSS injections, the first step of discovery is to examine the context in which the user input is injected, determine which special characters are allowed, which are disallowed (removed), and which are escaped and how.

User input is injected in two locations on the page, as illustrated below:

XSS injection context stated by screenshot of user input injection in the filter's JavaScript code.

The analysis of the JavaScript code reveals that the injection into the <span> tag uses innerText. This method automatically escapes HTML characters, making injection impossible here.

However, the second injection point occurs within a string in a <script> tag, in the definition of the username variable. Breaking out of this string allows for the execution of arbitrary JavaScript code.

To craft a functional injection, it is necessary to examine how the user input is processed. In this case, the processing is performed client-side, so simply reading the JavaScript code reveals the behavior. If it were performed server-side, testing would be required to discover how each special character is handled.

JavaScript
function escapeXss(input) {
    return input.replace(/"/g, '\\"').replace(/\//g, '\\/');
}

const params = new URLSearchParams(window.location.search);
const usernameParam = params.get('username');
const escapedUsername = usernameParam ? escapeXss(usernameParam) : 'ANONYMOUS';

var script = document.getElementById("user-script")
script.innerText = script.innerText.replace("PLACEHOLDER",escapedUsername)
eval(script.innerText)

Two treatments are applied to the user input before reinjecting it into the script tag:

  • " is replaced by \", preventing the escape of the string ;
  • / is replaced by \/, blocking the creation of closing HTML tags and JavaScript comments.

The first step in crafting the payload relies on a common filter bypass: " is escaped by adding \ before it, but the \ itself is not escaped. Therefore, the input \" becomes \\\". The added \ is escaped, and the " is interpreted again to close the string. Testing this in the lab leads to a JavaScript syntax error:

Crafting a functional payload for XSS injection by escaping the string in the JavaScript code of the custom filter.

The \ added before the final " in the payload — which allows reopening the string so that the existing " in the script does not cause issues — is not within a string and is invalid in JavaScript syntax. The injected code is not interpreted but instead throws an error in the console.

A solution to address this error is to comment out the rest of the line so that the closing " of the string is no longer interpreted. However, JavaScript comments (whether // or /* ... */) begin with /, which poses the same syntax problem as ", since the filter prepends them with \.

The trick to use is less common than the \ escape used earlier: we will comment out the end of the line using the HTML parser. Indeed, HTML comments do not use / but are opened with <!--, and the browser automatically closes them at the end of the tag:

Performing XSS injection through commenting in the JavaScript code of the custom filter.

As explored and proven in this case study, using custom filters to protect applications is ineffective and not recommended. Modern programming languages and frameworks provide specific functions that ensure optimal protection against injections. These tools should be favored to guarantee robust security and reduce the risks associated with XSS vulnerabilities or other types of injections.

Amos GEORGE, Audit & Offensive Security, I-TRACING

10 February 2026