Skip to main content

Insecure Processing of Data

This category covers the following issues:

Fixing Cross-Site Scripting

About XSS

What is Cross-Site Scripting?

Cross-site scripting (XSS) is a type of security vulnerability that allows attackers to inject malicious code into web pages viewed by other users. This occurs when an application fails to properly sanitize user input and injects untrusted data into a web page without validating or encoding it.

XSS attacks can occur in different forms, such as reflected, stored, or DOM-based, and can affect various types of web applications, including social media, e-commerce, and online banking sites.

Attackers can use various techniques, such as phishing emails, web forms, or malicious links, to trick users into visiting or interacting with web pages that contain malicious code.

Check out this video for a high-level explanation:

What is the impact of Cross-Site Scripting?

Cross-site scripting (XSS) can lead to various security threats and risks, such as:

  • Information theft: XSS attacks can steal sensitive information, such as login credentials, credit card details, or other personally identifiable information, by injecting malicious code that collects and transmits user data to attackers.
  • Account hijacking: XSS attacks can hijack user sessions by injecting malicious code that takes over user sessions, allowing attackers to perform unauthorized actions on the website or gain access to user accounts.
  • Data tampering: XSS attacks can modify or delete data on a website by injecting malicious code that alters the content of web pages, leading to data tampering, data corruption, or other types of malicious activities.
  • Malware distribution: XSS attacks can distribute malware by injecting malicious code that downloads and installs malicious software on the user's computer, leading to malware infections or other types of cyber attacks.

Overall, XSS attacks can compromise the confidentiality, integrity, and availability of data, leading to a range of security threats and risks.

How to prevent Cross-Site Scripting?

To prevent XSS vulnerabilities, you can take the following steps:

  • Input validation and sanitization: Ensure that all user input is validated and sanitized before being used to generate web pages or manipulate other data. Input validation should include validating the data type, length, and format, and filtering out any special characters that could be used to inject malicious code.
  • Output encoding: Encode all output to protect against XSS attacks. Use output encoding techniques such as HTML entity encoding, URL encoding, and JavaScript encoding to encode user input and output to the browser.
  • Use security headers: Implement security headers to protect against XSS attacks, such as Content-Security-Policy (CSP) and X-XSS-Protection. CSP can help prevent XSS attacks by allowing only trusted sources of content to be loaded on a page, while X-XSS-Protection can help prevent the browser from rendering pages that contain malicious scripts.
  • Session management: Implement secure session management mechanisms, such as session cookies, to protect against session hijacking and other attacks.
  • Secure coding practices: Use secure coding practices to prevent XSS vulnerabilities. This includes using libraries and frameworks that are designed to prevent XSS attacks, testing code for vulnerabilities, and using secure coding practices such as input validation and output encoding.
  • Regular security audits: Regularly audit your system for security vulnerabilities, including XSS vulnerabilities. Use automated tools and manual testing to identify potential issues and fix them before they can be exploited.

References

Taxonomies

Explanation & Prevention

Training

Category-specific resources:

Cross-Site Scripting (Handlebars)

Rule-specific resources:

Option A: Don't use Handlebars.SafeString (Backend)

Using Handlebar's default behavior of treating the input as pure text is the safest way to fix this vulnerability.

Note that if you want HTML content to appear, you should look at option B and sanitize the user input.

  1. Go through the issues that GuardRails identified, for a pattern similar to the following:

    app.get("/render", function(req, res) {
    let template = Handlebars.compile('This is some bold text: <b>{{input}}</b>')
    // Insecure example
    let value = new Handlebars.SafeString(req.body.untrustedValue)

    res.set("Content-Type", "text/html")
    res.send(template({input: value}))
    })
  2. Remove Handlebars.SafeString

    app.get("/render", function(req, res) {
    let template = Handlebars.compile('This is some bold text: <b>{{input}}</b>')
    // Secure example
    let value = req.body.untrustedValue

    res.set("Content-Type", "text/html")
    res.send(template({input: value}))
    })
  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Don't use Handlebars.SafeString (Frontend)

The safest way to fix this vulnerability is by using Handlebars' default behavior of treating any input as pure text.

Note that if you want HTML content to appear, you should look at option B and sanitize the user input.

  1. Locate the vulnerable pattern (example below):

       function render() {
    let template = Handlebars.compile('This is some bold text: <b>{{input}}</b>')
    let request = fetch("http://example.com/example.txt")
    .then(body => body.text())
    .then(text => new Handlebars.SafeString(text))
    .then(sstring => template({input: sstring}));
    }
  2. Replace it with one of the following patterns (example below):

    Example #1

       function render() {
    let template = Handlebars.compile('This is some bold text: <b>{{input}}</b>')
    let request = fetch("http://example.com/example.txt")
    .then(body => body.text())
    .then(text => template({input: text}));
    }

    Example #2

       function render() {
    let template = Handlebars.compile('This is some bold text: <b>{{input}}</b>')
    let request = fetch("http://example.com/example.txt")
    .then(body => body.text())
    .then(Handlebars.Utils.escapeExpression)
    .then(text => new Handlebars.SafeString(text))
    .then(text => template({input: text}));
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Sanitize your input

This option should be used if you want some input to be interpreted as HTML content. You can use a sanitizer such as DOMPurify to make sure any HTML is sanitized before it is embedded into the DOM.

Some possible options for sanitizing HTML include:

  1. Go through the issues that GuardRails identified, for a pattern similar to the following:

    // Backend example
    app.get("/render", function(req, res) {
    let template = Handlebars.compile('This is some bold text: <b>{{input}}</b>')
    // Insecure-example
    let value = new Handlebars.SafeString(req.body.untrustedValue)

    res.set("Content-Type", "text/html")
    res.send(template({input: value}))
    })
    // Frontend example
    function render() {
    let template = Handlebars.compile('I want custom HTML: <b>{{input}}</b>')
    let request = fetch("http://example.com/example.txt")
    .then(body => body.text())
    .then(text => new Handlebars.SafeString(text))
    .then(sstring => template({input: sstring}));
    }
  2. Sanitize user input before passing it to Handlebars.SafeString

    // Backend example
    const DOMPurify = require('isomorphic-dompurify');

    app.get("/render", function(req, res) {
    let template = Handlebars.compile('This is some bold text: <b>{{input}}</b>')
    // Secure examples
    let value = DOMPurify.sanitize(req.body.untrustedValue)
    value = new Handlebars.SafeString(value)

    res.set("Content-Type", "text/html")
    res.send(template({input: value}))
    })
    // Frontend example
    function render() {
    let template = Handlebars.compile('I want custom HTML: <b>{{input}}</b>')
    let request = fetch("http://example.com/example.txt")
    .then(body => body.text())
    .then(DOMPurify.sanitize)
    .then(text => new Handlebars.SafeString(text))
    .then(sstring => template({input: sstring}));
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Cross-Site Scripting (Frontend)

Injecting unsanitized HTML from untrusted sources into the DOM without prior sanitization can lead to Cross-Site Scripting vulnerabilities.

Option A: Treat all data purely as text

The safest way to fix this kind of vulnerability is to simply use methods/properties that will treat all your data as text (not as HTML). These include:

  • document.createTextNode(<UNTRUSTED_INPUT>)
  • Node.textContent = <UNTRUSTED_INPUT>

Note that document.createTextNode(...) creates a Node object that can be used in the DOM whereas the other properties simply overwrite the content inside the selected element/node. selected.

Another option that you can use is innerText or outerText, note, however, that these elements are susceptible to forms of XSS

  • HTMLElement.innerText = <UNTRUSTED_INPUT>
  • HTMLElement.outerText = <UNSTRUSTED_INPUT>
  1. Locate the vulnerable pattern (example below):

    async function updateComment(id) {
    let data = await fetch(`api.example.com/v1/comments/${id}`);
    // Vunerable line of code here
    document.getElementById("comments").innerHTML = await data.text();
    }
  2. Replace it with one of the following patterns (example below):

    Example #1 (using HTMLElement.textContent)

    async function updateComment(id) {
    let data = await fetch(`api.example.com/v1/comments/${id}`);
    // Fixed
    document.getElementById("comments").textContent = await data.text();
    }

    Example #2 (using document.createTextNode(...)

    async function updateComment(id) {
    let data = await fetch(`api.example.com/v1/comments/${id}`);
    // Fixed
    let node = document.createTextNode(await data.text());
    document.getElementById("comments").appendChild(node)
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Sanitize your HTML

This option should be used if you want some input to be interpreted as HTML content. You can use a sanitizer such as DOMPurify to make sure any HTML is sanitized before it is embedded into the DOM.

Some possible options for sanitizing HTML include:

  1. Locate the vulnerable pattern (example below):

    async function updateComment(id) {
    let data = await fetch(`api.example.com/v1/comments/${id}`);
    // Vunerable line of code here
    document.getElementById("comments").innerHTML = await data.text();
    }
  2. Replace it with one of the following patterns (example below):

    async function updateComment(id) {
    let data = await fetch(`api.example.com/v1/comments/${id}`);
    // Fixed
    document.getElementById("comments").innerHTML = DOMPurify.sanitize(await data.text());
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Cross-Site Scripting (React)

Inserting raw HTML via dangerouslySetInnerHTML can lead to Cross Site Scripting vulnerabilities.

Rule-specific references:

Option A: Don't use dangersouslySetInnerHTML

The safest way to fix this kind of vulnerability is to simply not use dangerouslySetInnerHTML. If you don't require your input to be able to customize HTML then you're fine.

  1. Locate the vulnerable pattern (example below):

    function Comment({username, message}) {
    let inner = `<b>${username}</b>: <span style='color: blue'>${message}</span>`
    return <div dangerouslySetInnerHTML={{__html: inner}}/>
    }
  2. Replace it with a pattern similar to the one below:

    function Comment({username, message}) {
    return (<div>
    <b> {username} </b>
    <span style='color: blue'>{message}</span>
    </div>);
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Sanitize the user input

Some possible options for sanitizing HTML include:

  1. Locate the vulnerable pattern (example below):

    function Comment({username, message}) {
    let inner = `<b>${username}</b>: <span style='color: blue'>${message}</span>`
    return <div dangerouslySetInnerHTML={{__html: inner}}/>
    }
  2. Replace it with one of the following patterns (example below):

    import * as DOMPurify from 'isomorphic-dompurify';

    function Comment({username, message}) {
    let inner = `<b>${username}</b>: <span style='color: blue'>${message}</span>`
    return <div dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(inner)}}/>
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Option C: Use a different form of customization

This option should be used if you want HTML content to be customized by your input. Instead of allowing input to use HTML for customization, you can switch to using something like react-markdown, and the input can be embedded through markdown (much safer).

  1. Locate the vulnerable pattern (example below):

    function Comment({username, message}) {
    let inner = `<b>${username}</b>: <span style='color: blue'>${message}</span>`
    return <div dangerouslySetInnerHTML={{__html: inner}}/>
    }
  2. Replace it with one of the following patterns (example below):

    import ReactMarkdown from 'react-markdown'

    function Comment({username, message}) {
    return (<b>{username}:</b>
    <ReactMarkdown>{message}</ReactMarkdown>);
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Cross-Site Scripting (Generic)

Option A: Ensure Unescaped Variables are Safe

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Identify the code with one of these patterns:

    // Dust.js
    {variable}
    // Pug.js
    !{variable}
    // ECT templates
    <% ... >
    // EJT templates
    <% ... >
  3. And ensure that all of these unescaped variables don't contain any unsanitized user input

  4. Test it, ship it 🚢 and relax 🌴

Option B: Ensure XSS Security Headers are enabled

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Identify the code with one of these patterns:

    // XSS Security Headers
    lusca.xssProtection(false);
    X-XSS-Protection = 0;
  3. And ensure the headers are enabled. Note: It may be possible that this is handled on the load balancer or web server level

  4. Test it, ship it 🚢 and relax 🌴

Option C: Ensure No User Input is Passed to res()

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Identify the code with one of these patterns:

    res.write(req.body.evil);
    res.send();
  3. And ensure that no user input is passed to these functions

  4. Test it, ship it 🚢 and relax 🌴

Option D: Perform Output Encoding

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Identify code that matches *.escapeMarkup = false:

    var template: Object = new Object();
    template.escapeMarkup = false;

    And replace it with *.escapeMarkup = true,

    template.escapeMarkup = true;

    Setting escapeMarkup = false can be used with some template engines to disable escaping of HTML entities which could potentially lead to Cross-Site Scripting (XSS) vulnerabilities.

  3. Identify code that matches any of the following patterns:

    document.write(variable);
    document.writeln(variable);
    Element.innerHTML = variable;
    Element.outerHTML = variable;
    el.insertAdjacentHTML(variable);

    For example:

    var element: Element = document.getElementById("mydiv");
    var content: String = "some content";
    Element.innerHTML = content;

    Ensure that the content is not coming from request parameters, and is sanitized and escaped before being passed to the affected method

  4. Test it

  5. Ship it 🚢 and relax 🌴

Fixing Server-Side Request Forgery

About SSRF

What is Server-Side Request Forgery (SSRF)?

Server-Side Request Forgery (SSRF) is a type of web application vulnerability that occurs when an attacker can manipulate the server-side code to make it perform unauthorized HTTP requests to other web applications. SSRF attacks can allow an attacker to send requests from the vulnerable server to internal or external network resources, which can result in data leaks, access to sensitive data or even compromise the entire network.

An SSRF attack typically involves an attacker tricking a server into making a request to a specific URL that the attacker controls. The attacker may do this by manipulating the parameters of a URL or by using other techniques to inject malicious code into the server-side code.

What is the impact of Server-Side Request Forgery (SSRF)?

Attackers can use this vulnerability to perform a variety of attacks, such as:

  • Information disclosure: The attacker can use an SSRF attack to access sensitive data, such as configuration files, internal documentation or even credentials, which can be used to compromise the entire network.
  • Port scanning: The attacker can use an SSRF attack to scan the network for open ports, which can be used to identify potential vulnerabilities in the system.
  • Bypassing authentication and authorization: An SSRF attack can be used to bypass authentication and authorization controls by sending requests to internal services that do not enforce these controls.
  • Exploiting internal APIs: An SSRF attack can be used to exploit unprotected internal APIs, which can result in unauthorized access to sensitive information or actions that the user is not authorized to perform.
  • Denial-of-service (DoS): The attacker can use an SSRF attack to flood the targeted web application with requests or to perform a request to a resource that is not available, causing the application to crash or slow down.

How to prevent Server-Side Request Forgery (SSRF)?

Here are some best practices to prevent SSRF attacks:

  • Use secure APIs: Use secure APIs that do not allow arbitrary URLs to be passed as parameters. This can prevent attackers from manipulating the server-side code to perform unauthorized HTTP requests.
  • Input validation and sanitization: Validate and sanitize all user input, especially for URLs, to ensure that they are valid and safe. This can prevent attackers from injecting malicious URLs into the server-side code.
  • Access controls: Implement access controls to limit access to only authorized users. This can prevent attackers from exploiting unprotected internal APIs or cloud infrastructure.
  • Server hardening: Harden servers by removing unnecessary software and services, and limiting access to administrative interfaces. This can prevent attackers from exploiting vulnerabilities in the server-side code or gaining access to sensitive information.
  • Network segmentation: Use network segmentation to prevent web applications from accessing internal resources or those that they do not need to access. This can limit the impact of an SSRF attack by preventing the attacker from accessing sensitive resources.

References

Taxonomies

Explanation & Prevention

Training

Option A: Ensure that User Controlled Data is Sanitized

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Identify the code with one of these patterns:

    request(req.body.evil);
    request.get();
    needle.get();
  3. And replace any dynamic user input with either a list of allowed options that is referenced by a UUID, or alternatively, re-write the code to ensure no dangerous or unauthorized functionality can be triggered by users

  4. Test it, ship it 🚢 and relax 🌴