So you think cross-site scripting isn’t a big deal?

Far from being low-priority issues, cross-site scripting vulnerabilities in your websites and applications can directly put your users and customers at risk. This post goes through just one possible attack scenario to show how dangerous XSS can be.

So you think cross-site scripting isn’t a big deal?

Cross-site scripting (XSS) vulnerabilities have always been the most numerous class of web application security issues. They are easy to introduce but much harder to find and remediate, which increases the risk of them making it into production code. This is reinforced by the misconception that web security is all about protecting the server, and since XSS can only affect the client, it is a low-risk vulnerability with limited impact.

In reality, cross-site scripting can be (and is) used by cybercriminals as a stepping stone to more elaborate attacks targeted at end users. Simply put, if you have XSS vulnerabilities in your websites and applications, you are putting your users at risk and making the job of malicious hackers much easier. To illustrate just how easy it can be, we asked Invicti security researcher Sven Morgenroth for a snippet of JavaScript code that, while harmless in itself, could also be put to malicious use in a realistic attack scenario – and the conclusions are chilling.

Innocent yet dangerous – some quirky code

In case you’re not familiar with cross-site scripting payloads, they are snippets of JavaScript code that can be injected into a vulnerable site, causing the browser to perform specific actions. “Malicious payloads often exploit quirky browser behavior to evade built-in security controls,” says Morgenroth. “A good example of this is how the beforeunload event is handled. It is designed as a way to show a prompt before you leave a page to warn you about unsaved changes. You are not supposed to use it for anything else or put any custom code in the event handler, but browsers don’t enforce this fully, so you can find ways around it.”

As it turns out, you can make an asynchronous function call using setTimeout(), and it will not be blocked by the browser. Instead, it will run just before the page unloads. Here is a sample code snippet that triggers a redirect to example.com, though it could be any other URL:

window.addEventListener('load', () => {
    window.addEventListener('beforeunload', function (e) {
        e.preventDefault()
        setTimeout(() => window.location = 'https://example.com/')
    })
})

“As soon as the page loads, the script adds code that listens for the beforeunload event and changes the page URL when that event occurs,” explains Morgenroth. “So you have a valid piece of JavaScript that you can put on a web page, and it will sit there waiting for you to click away or type a different URL in the address bar. As soon as you do, the script will redirect you to an arbitrary site.”

From cool trick to attack payload

Interesting though it is to trick the browser into unexpected behavior, you first need to get the browser to load that code. For an attacker, this could mean building a malicious URL and tricking a user into opening it. The example code would also need a bit of work to weaponize it into a real-life injectable payload. According to Morgenroth, “XSS payloads are typically encoded, sometimes more than once, to ensure they are accepted by the application and also to help evade filters. The code can also be minified to make it as short as possible.”

First and foremost, though, to build the URL, attackers need to find a page that is vulnerable to cross-site scripting and therefore happy to accept the injected script. It also needs to be a page that someone would legitimately want to visit so they can be more easily tricked into following a malicious link. If you have an XSS vulnerability in your web environment, cybercriminals can target your users or customers via one of your vulnerable sites – and with large organizations running over a hundred websites and applications on average, the odds of finding an opening are in favor of the attackers.

Let’s run through a hypothetical but fully realistic attack scenario to see what can happen and how.

Realistic attack scenario: phishing + XSS

Having found an XSS vulnerability in one of your sites, the attackers prepare a spear phishing campaign targeting your company’s current customers. Using open-source intelligence (OSINT) or simply a stolen customer list, they send each of your customers a carefully spoofed marketing email announcing a new research report that promises to reveal eye-opening industry insights. The message contains a button labeled Read the report now that points to your site, specifically to a page something like this:

https://your-company-site.com/research/new-research-reveals-dangerous-industry-trends?utm=mktemail&utm2...

The URL is very long and isn’t displayed in its entirety, so your customer doesn’t see the encoded attack payload at the end (and it would be a random-looking string of characters anyway). Crucially, this page has an XSS vulnerability that is ready to accept the injected code – except this time, the payload redirects users not to example.com but to a malicious site that attempts a drive-by malware download.

The customer is unlikely to suspect the URL because it points at your site, which they know and trust. And if the phishing email is carefully prepared, it might all look legitimate, maybe even down to saying it’s a PR agency mailing on your behalf (to explain why the email comes from a different domain). If the report seems relevant, the customer clicks the button and an existing page on your site opens in their browser – and because the page is vulnerable, the malicious redirect code also loads, quietly sitting in the beforeunload event handler and waiting.

Now comes the sting. When your customer realizes this is not the promised report page, they will assume somebody in marketing has entered the wrong URL, so they are likely to start clicking around your site to actually find that report (because they know the site and trust it). As soon as they navigate away from the page, the listener script fires and they are redirected to a malicious site that installs malware in their browser or even their operating system. This could be anything – a botnet client, a cryptojacking script, a web shell for further attacks, or even a ransomware downloader.

One of your customers has just been hacked – and it looks like the attack came from your site.

The risk is real, as are the consequences

Phishing attacks are among the top cybersecurity threats overall, having tripled in number since 2020. While more often associated with attempts to steal credentials or perform various scams, phishing is also the perfect way to deliver XSS attack payloads since cross-site scripting generally requires user interaction (at least for the most common reflected XSS). The scenario presented here abuses the trust your customers have in your site and brand to get them to click a malicious link. Your vulnerable site is then the vehicle for an attack on one of your customers, so while it’s true that your own systems are not attacked or affected in any way, your customers are at risk. Attackers can elicit sensitive data, rewrite your page content in the browser to misinform users, or even hijack a user session to access restricted information or systems.

A simple redirect is only one example of what an XSS payload can do. Depending on the specific vulnerability and payload, threat actors have many other options to choose from. For instance, instead of an immediate redirect, the same attack could start by rewriting your company page as it loads and presenting a perfectly plausible message like Redirecting you to popular-social-site.com/your-company. If the page doesn’t load in 5 seconds, please click the link below or manually paste the URL into the address bar.

Not one but two malicious redirects could then be hidden on that rewritten page. One would be triggered by the click event on the link so that if you hover over the link to check it, you see a safe URL – but when you click it, you go to a malicious page. For the other redirect, we have our old friend, the beforeunload event, to catch you when you type or paste the URL. The user is given the illusion of choice but, either way, ends up on a malicious site that can harm them.

So while it’s technically true that XSS attacks only affect the client browser, the consequences for your business and reputation can be serious. Especially with a coordinated phishing campaign, attackers are piggybacking on your customers’ trust in your company – and by having exploitable XSS vulnerabilities in your sites or applications, you are undermining that trust. In this specific example, you could even be required to perform forensics to prove that your site was not the source of the attack, and you are not liable for any harm done to your customers’ systems and data. And even then, your customer relationships are likely to have soured, and winning back trust and reputation could be difficult and costly.

Don’t put your users at risk – fix those XSS issues

“In the past, cross-site scripting vulnerabilities were treated as a necessary evil in web development, not as serious defects,” concludes Morgenroth. “Code reviews and manual penetration tests were the only ways to find XSS, so it took a lot of work and time to fix what was seen as a relatively minor issue.” Today, advanced tools for dynamic application security testing (DAST) can automatically and accurately identify all manner of XSS vulnerabilities in any number of sites, so clamping down on cross-site scripting is finally a realistic prospect.

As shown in this post, leaving XSS vulnerabilities in your web applications means putting your customers and your reputation at risk. Luckily, with modern advances in vulnerability scanning, your developers can finally cut into their XSS backlog by getting actionable reports that help them implement long-term fixes and avoid the same mistakes in the future. You don’t need to wait for the next penetration test – scan for vulnerabilities as often as you want, from your first builds to your production deployment, and fix the issues that are reported.

With an industry-leading vulnerability scanner like Invicti, XSS vulnerabilities are low-hanging fruit for quick and significant security improvements. So find them and fix them. No more excuses.

Zbigniew Banach

About the Author

Zbigniew Banach - Senior Technical Content Writer

Cybersecurity writer at Invicti Security. Drawing on years of experience with security, software development, content creation, journalism, and technical translation, he does his best to bring web application security and cybersecurity in general to a wider audience.