Having small XSS payloads or ways to shorten your payloads ensures that even the smallest unencoded output on a site can still lead to account compromise. A typical image tag with a onerror attribute takes up around 35 characters by itself.

<img src=1 onerror="alert('XSS')"> If you would like to prove you can steal credentials or change the source of a page, you may need to have a few different methods in your pocket to get a working payload if your input is limited to say, 50 characters. What can we do with those remaining 15-16 characters?

As a disclaimer, the domains used in this article are examples and not explicitly owned by me or TrustedSec. If you end up trying any of the payloads mentioned in this blog, it is advised you change the domain or IP used to an endpoint you are authorized to use.

Output encoding and sanitization are typical recommendations to prevent client-side vulnerabilities. As an additional security measure, user inputs have character limitations to prevent misuse. For example, it might be a zip code that only allows a 10-character maximum.

Another effective way to prevent XSS is by configuring a Content Security Policy (CSP). A correctly configured CSP can prevent external script execution and other content from retrieving data from external domains. A CSP can also prevent scripts from being executed for sources that have not exclusively been defined. However, due to the amount of third-party software in modern applications, most CSPs are not very strict and still allow an attacker the ability to perform XSS. A combination of these security configurations can prevent larger XSS payloads from executing.

Let’s consider the following: A site has a blog that you can enter comments into. To submit a comment, you are required to put your first name, last name, and email address, as well as what comment you would like to add. The site encodes any input you enter into the comments sections to prevent XSS.

Through testing the application, you find that the first and last name fields are vulnerable to XSS and have character limitations of no more than 50 characters. In testing, you find you can submit your last name with a common payload to display an alert.

Payload:

<img src=1 onerror=alert('XSS')> Figure 1 – XSS Payload in InputFigure 2 – XSS Alert in Displayed UsernameSo, we’re done. We got XSS, and we can move on. But we can’t make a request on behalf of an admin or change the page source with an alert. Let’s try to actually show some impact. Instead of implying what could be done with an XSS vulnerability, let’s create a proof-of-concept.

So first off, we can try to load some external scripts since we don’t have enough space to write out the few lines of JavaScript it might take to make a fetch request on behalf of the user. We can do this by adding a script tag.

```

``` Right off the bat, we run into an issue. This payload is too long for the user’s last name. So, what are our options? First, try to shorten the payload by getting rid of anything that’s not needed.

Something more like this:

```

``` We removed the quotes around the payload because similar to a command line function. As long as you don’t have any spaces in your URL, the browser will add them for you. Next, we changed our protocol from http to https. In this case, we can assume that we control the content on the server that we are setting as the source, and because we can control incoming requests, we can easily set up a URL redirect for any http request to https. In some cases, the browser may throw a mixed-content error due to the fact you are trying to load in content from an unencrypted source. In those cases, it may be required to leave the protocol as https.

Then, we removed the forward slashes from the URL scheme. We did this because if we have a valid protocol followed by a colon, most browsers will add the slashes before the domain path.

Now to shorten the domain and path of the URL. There are many ways to do this, and the above payload could be even shorter if we had control of a short domain name and removed any subdomains. Furthermore, because we control the external domain, we could make our site return a JavaScript content type and serve up our XSS payload on the home page of the domain to eliminate the path completely.

Making the homepage return a JavaScript file in Express.js can look something like this:

Figure 3 – Hosting a JavaScript File as the HomepageFigure 4 – Contents of test.jsWith all of these redactions, we end up with something like the following script tag with only 34 Characters.

```

``` Another thing that can be done is that modern browsers are very helpful and try to add any missing or incomplete tags. For example, if a label is meant to be bolded but the end tag is missing, the browser will add one.

So,

<label><b>Bold Me</label> Will be changed to:

<label><b>Bold Me></b><label> In some cases, we can use this to our advantage by not adding end tags to our payload but do this at your own risk. Depending where the XSS is located on the page, it may “eat” sections of the original page content. If no ending script tag is added, the browser will end up putting the content that is after our starting script tag into the body of our tag. This can make the page not render properly. In some cases, this may include only a few lines of HTML and other times it will contain the entire rest of the page. It depends on where the next script tag is located after our XSS. An example payload would look like this:

```