top of page

The Most Overlooked Spots for XSS Vulnerabilities in Your Web Applications

Cover image for blog about the most overlooked cross scripting (XSS) vulnerabilities

Cross-Site Scripting (XSS) vulnerabilities are akin to digital landmines—hidden in unexpected places, ready to be set off by an unsuspecting user. Although many developers are familiar with the typical locations where XSS vulnerabilities might be found, certain areas are often neglected, resulting in significant security threats. Let’s explore and expose these concealed vulnerabilities.


Error Messages and Pop-ups

Developers often overlook error messages as potential vectors for XSS attacks. These messages frequently display user inputs to inform users of issues—such as invalid entries or system errors—without considering the security implications. As it was with our recent CVE identified for the large open-source library n8n. This library allows users to chain commands for tasks like data extraction.


Now, what if you insert an <a> tag containing a simple JavaScript code as the value of the href attribute into an input field? When the application triggers an error, the unescaped input could be displayed in a popup message, resulting in the execution of the malicious code. In this scenario, an attacker could use social engineering to craft a message that lures a user into clicking a hyperlink, leading to the execution of harmful JavaScript.


Data Imported from External Sources

Data imported from external sources, such as CSV files, is often treated as trustworthy. However, this can be a dangerous assumption. Attackers can inject XSS payloads into these files, which are then executed when the data is processed or displayed in an application.


Let’s take a closer look:

Imagine your application allows users to import data, such as comments or profiles, from external sources. What if that data contains embedded scripts? For example, an attacker could inject an XSS payload into their Steam profile. When logging in via Steam SSO on your platform, this malicious script could be executed, compromising user accounts.


Here’s how it could happen:

To demonstrate, let’s create a simple HTML page that imitates a Steam SSO form:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Steam SSO Example</title>
</head>
<body>
    <h1>Login with Steam</h1>
    <p>Click the button below to log in with your Steam account:</p>
    <a href="<http://localhost:3000/auth/steam>">
        <img src="<https://steamcommunity-a.akamaihd.net/public/images/signinthroughsteam/sits_large_noborder.png>" 
             alt="Sign in through Steam">
    </a>
</body>
</html>


We’ll also need a server to handle our OAuth flow. Let’s mock that as well:

const express = require('express');
const app = express();
const port = 3000;

// Serve the HTML file
app.get('/', (req, res) => {
    res.sendFile(__dirname + '/index.html');
});

// Mock Steam SSO Redirect
app.get('/auth/steam', (req, res) => {
    // Simulate Steam redirect with a vulnerable full name
    const xssPayload = '<script\\x20type="text/javascript">javascript:alert(1);</script>';
    res.redirect(`/auth/steam/callback?openid.identity=https://steamcommunity.com/openid/id/1234567890&fullname=${encodeURIComponent(xssPayload)}`);
});

// Mock Steam SSO Callback
app.get('/auth/steam/callback', (req, res) => {
    const steamId = req.query['openid.identity'].split('/').pop(); // Extract the mock Steam ID
    const fullName = req.query['fullname']; // Extract the mock full name, vulnerable to XSS

    // Deliberately unsafe rendering of the full name
    res.send(`
        <h1>Welcome, Steam User!</h1>
        <p>Your Steam ID is: ${steamId}</p>
        <p>Your Steam Account Full Name is: ${fullName}</p> <!-- XSS vulnerability here -->
    `);
});

// Start the server
app.listen(port, () => {
    console.log(`Mock Steam SSO server running at <http://localhost>:${port}`);
});

As you can see, we’re mocking the fullname payload from Steam and returning it to the application. Often, this input is untrusted, leading to XSS vulnerabilities as shown below.



HTML Email Generation

HTML emails are often generated dynamically, and any user input included can lead to XSS or HTML injection.


Consider this scenario:

You’re building a web application that allows users to send personalized HTML emails, such as order confirmations or invitations. Users can customize the content, including their name, message, and a link to a website. But what if a malicious user decides to exploit this feature by inserting a script in the "Website" field?


Let’s say the user inputs the following:

Name: John Doe
Message: Click the link below to confirm your registration:
Website: <script>window.location.href='<http://malicious-site.com>';</script>

Your application generates the following HTML email:

<!DOCTYPE html>
<html>
<head>
    <title>Registration Confirmation</title>
</head>
<body>
    <h1>Welcome, John Doe!</h1>
    <p>Click the link below to confirm your registration:</p>
    <p><a href="<script>window.location.href='<http://malicious-site.com>';</script>">Confirm Registration</a></p>
    <p>Thank you for registering with us!</p>
</body>
</html>

When the recipient opens the email and clicks the "Confirm Registration" link, the script is executed, and the user is redirected to the malicious website.


This type of vulnerability could lead to the recipient being redirected to a phishing website that looks like the legitimate site but is designed to steal personal information, such as login credentials or payment details. It could also cause the recipient to lose trust in the original platform, as they might believe it was responsible for the malicious redirection.


Server-side XSS in file generation

When creating documents, especially PDFs, developers might not initially consider the potential for XSS risks. However, server-side XSS can pose a serious threat, particularly when a headless browser is employed to render HTML into files.


Consider a scenario where you're developing a web application that generates PDF reports based on user input. The application utilizes a headless browser, like Puppeteer, to convert HTML content into a PDF.


But what if an attacker manages to inject a malicious script into the HTML content?

<script>
x = new XMLHttpRequest();
x.onload = function() { document.write(btoa(this.responseText)) };
x.open("GET", "file:///etc/passwd");
x.send();
</script>

Your server-side code, which generates the PDF, processes this input as follows:

const puppeteer = require('puppeteer');
const fs = require('fs');

async function generatePDF(userInput) {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    // Craft HTML content with user input
    const htmlContent = `
        <html>
        <head>
            <title>Report</title>
        </head>
        <body>
            <h1>Generated Report</h1>
            <div>${userInput}</div>  <!-- This is where the XSS vulnerability occurs -->
        </body>
        </html>
    `;

    // Set the content and generate the PDF
    await page.setContent(htmlContent);
    await page.pdf({ path: 'report.pdf', format: 'A4' });

    await browser.close();
    console.log('PDF generated: report.pdf');
}

// Example of malicious input
const maliciousInput = `
<script>
x = new XMLHttpRequest();
x.onload = function() { document.write(btoa(this.responseText)) };
x.open("GET", "file:///etc/passwd"); 
x.send();
</script>`;

generatePDF(maliciousInput);

When the headless browser processes this HTML to generate the PDF, the script is executed, potentially accessing sensitive files on the server, like /etc/passwd.


This type of vulnerability could lead to serious consequences, such as exposing sensitive data or compromising server integrity. By executing arbitrary JavaScript on the server, an attacker could access internal services or sensitive files, leading to further exploitation.


Cross-Site Scripting (XSS) Vulnerabilities: Wrapping It Up

XSS vulnerabilities are sneaky—often hiding in plain sight within your web applications. From error messages and data imports to HTML emails and server-side file generation, these overlooked spots can become gateways for attackers if not properly secured.


Let’s recap:

  • Error Messages and Pop-ups: Even the most routine error messages can expose your application to XSS attacks if user inputs are not sanitized.

  • Data Imported from External Sources: Trusting external data without proper validation can lead to XSS vulnerabilities, particularly when importing data from third-party platforms or files.

  • HTML Email Generation: Dynamically generated HTML emails that embed user inputs can open the door to phishing attacks and other XSS exploits if inputs aren't carefully validated.

  • Server-side XSS in File Generation: When generating files like PDFs, especially using headless browsers, malicious scripts can execute server-side, leading to serious security breaches.


The key to protecting your web applications from XSS vulnerabilities lies in vigilance. Always sanitize and validate user inputs, especially in areas that might be overlooked during development. By doing so, you can safeguard your application, protect your users, and maintain the integrity of your platform.

Stay vigilant and keep these spots on your radar—security is an ongoing effort, and every detail matters.


References

Related articles

Do you know all risks in your application?

Get a free threat modeling from our experts!

Got it! We'll process your request and get back to you.

bottom of page