Blog post

What is deeper SAST in JavaScript?

Blog Author Phil Nash

Phil Nash

Developer Advocate JS/TS

Date

  • JavaScript
  • TypeScript
  • Security

Deeper SAST expands the capabilities of Sonar's SAST to help you detect more security vulnerabilities in your JavaScript or TypeScript applications. Now you can discover and fix security issues that arise from interactions between your code and the third-party, open-source libraries you use.


This all sounds very useful, but what even is SAST? And how does deeper SAST improve things and help you write Clean Code in JavaScript or TypeScript?

What is SAST?

SAST stands for Static Application Security Testing. It's a form of white-box testing in which your application's source code is scanned for potential vulnerabilities. Writing Clean Code can help to ensure your application is free from these vulnerabilities and using SAST helps to detect issues as you build.


When you use SonarQube Server or SonarQube Cloud to analyse your source code, it uses static analysis to detect issues in your code that cause bugs and security vulnerabilities. There are two types of vulnerabilities that Sonar scans for:

Configuration vulnerabilities are often due to mistakes like using the wrong parameter when calling a sensitive function, whereas injection vulnerabilities are a bit more tricky.


Injection vulnerabilities are detected by a technique called taint analysis. Taint analysis determines whether potentially malicious user input makes it through your application to a sensitive output like a database or file system, or if it's used by the front end to generate the user interface.

Taint Analysis

Taint analysis detects the following in your application code:

  • User inputs to a system (sources)
  • Functions that make user input safe (sanitisers)
  • Functions that check to see if user input is safe (validators)
  • Sensitive functions that receive user input and could be exploited (sinks)

Once the analysis understands the sources, sanitisers, validators, and sinks in a system, it can track the user input from the source and ensure that it is either sanitised or validated before it is used as an argument to a sink. If user input makes it through to a sink without being sanitised or validated, then you have an injection vulnerability in your code.

Example

Let's see what this means in practice in a code base. Here is an excerpt from an Express application with a route that dynamically returns a file from the filesystem based on a query parameter. The code is intentionally simple and vulnerable to a path injection, also known as a directory traversal, attack.

// server.js
import Express from "express";
import { getImage } from "./image-fs.js";
export const app = Express();
app.get("/image", getImage);
// image-fs.js
import { stat } from "node:fs/promises";
import { createReadStream } from "node:fs";
import { fileURLToPath } from "node:url";
import { join } from "node:path";

const __dirname = fileURLToPath(new URL(".", import.meta.url));

export async function getImage(req, res) {
  const filename = String(req.query.filename);
  if (filename) {
    const file = join(__dirname, "..", "images", filename);
    try {
      const fsStat = await stat(file);
      if (fsStat.isFile()) {
        createReadStream(file).pipe(res);
      } else {
        res.status(404).json({ error: "file not found" });
      }
    } catch (error) {
      res.status(404).json({ error: "file not found" });
    }
  } else {
    res.status(400).json({ error: "filename is required" });
  }
}

The SonarQube Cloud analysis of this code looks like this:

A screenshot of a SonarCloud analysis of the above code. It shows that there is a source in server.js, where user input comes from the HTTP request. That input is then passed through to the getImages function which does not sanitise it before it makes a request to createReadStream to read a file. In this case the createReadStream function was imported from the standard library fs module.

SonarQube Cloud detects a source in server.js: the user controls the incoming HTTP request, so we cannot trust it. The user input is passed to the getImages function, which is concatenated with other data using the path module's join function. The resulting path is then passed to the fs module's createReadStream function, and the file contents are streamed to the response object and back to the user.


Because we never sanitise or check the data from the user, this code is vulnerable to a directory traversal attack illustrated in the SonarQube Cloud analysis. The code is supposed only to read files from the images directory, but if you, for example, pass a filename like "/images?filename=../package.json" then you will get back the project's package.json file. You can run this application and try it yourself with the source code available on GitHub.


This is a relatively simple issue, but it can be challenging to keep track of it in your head when user input passes through more functions and more files. That's where SAST comes in.

So what is deeper SAST?

Traditional SAST analyses your application code, but it does so with no understanding of your application's dependencies. It is rare to find a JavaScript or TypeScript application that doesn't use third-party libraries from npm. If you've ever peeked inside your node_modules directory, you will know intuitively that scanning all of those dependencies would be terrible for the performance of the scanning process.


However, we may miss out on potential vulnerabilities by treating our dependencies as safe black boxes. To counteract that, Sonar now pre-scans popular open-source libraries to find sources, sinks and sanitisers and makes that data available to our taint analysis engine. Sonar's taint analysis can then better understand the interactions between your code and your dependencies' code gaining a greater understanding of how user input enters your application, flows through it, and where tainted data might exit causing a vulnerability. Notably, deeper SAST does not look for vulnerabilities in the dependency code, instead, it finds interactions that can make your code vulnerable.


Deeper SAST enhances Sonar's taint analysis with deep knowledge about your dependencies to uncover hidden vulnerabilities.

Example

One of the dependencies that we now scan is fs-extra. This library wraps Node's fs module and adds extra file system functionality. You can use fs-extra as a drop-in replacement for fs, any function that fs-extra doesn't implement is passed on to fs. These are the changes I made to the code:

- import { stat } from "node:fs/promises";
- import { createReadStream } from "node:fs";
+ import fsExtra from "fs-extra";
+ const { stat, createReadStream } = fsExtra;

As you can see, I have only changed the imports. The actual code has stayed the same, but with traditional SAST the vulnerability would no longer be detected.


Now with deeper SAST, the vulnerability is caught just like the direct call to the fs module. All the additional fs-extra functions are also covered, so path traversal vulnerabilities will be detected when using potentially dangerous functions like remove.

A screenshot of a SonarCloud analysis of the above code. It shows that there is a source in server.js, where user input comes from the HTTP request. That input is then passed through to the getImages function which does not sanitise it before it makes a request to createReadStream to read a file. In this case the createReadStream function was imported from the third-party fs-extra module.


In the above screenshot, we see the results of scanning a file called image-fs-extra.js. This file is using fs-extra instead of the fs module and the vulnerability is still caught. You can check out the full source code of this project on GitHub and see the analysis results in SonarQube Cloud.

Clean Code is secure code

Avoiding injection attacks is a case of understanding how user input flows into and through your application and always sanitising or validating it before it is sent to sinks like functions that deal with the file system or databases. SAST can help you detect these application issues by tracking tainted data across functions and files. Deeper SAST goes further by understanding popular open-source libraries and their sources of tainted data or potentially vulnerable sinks.


Sonar's SAST is available in SonarQube Cloud and the commercial editions of SonarQube Server, and deeper SAST is available for JavaScript and TypeScript, as well as Java and C# projects, for no additional cost. Learn more about deeper SAST at Sonar.


Get new blogs delivered directly to your inbox!

Stay up-to-date with the latest Sonar content. Subscribe now to receive the latest blog articles. 

By submitting this form, you agree to the storing and processing of your personal data as described in the Privacy Policy and Cookie Policy. You can withdraw your consent by unsubscribing at any time.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

  • Legal documentation
  • Trust center
  • Follow SonarSource on Twitter
  • Follow SonarSource on Linkedin

© 2008-2024 SonarSource SA. All rights reserved. SONAR, SONARSOURCE, SONARQUBE, and CLEAN AS YOU CODE are trademarks of SonarSource SA.