Automate JavaScript scanning with Retire.js in Azure DevOps
Every web developer uses a lot of JavaScript libraries. When installing packages from npm, it almost feels like you are downloading half of the libraries there. Like every other piece of code, JavaScript can include vulnerabilities that make hackers drool and eager to start exploiting your site. In this post, I'll show you how to detect JavaScript libraries with known vulnerabilities and how to automate the process on Azure DevOps.

There are different ways of figuring out if you include JavaScript libraries with vulnerabilities in your website. npm comes with npm audit
which does exactly this, but it is limited to the packages referenced in a package.json
file. In .NET, some may use this while other uses solutions like manually copying and pasting JavaScript libraries or installing them through libman. For this post, I'll introduce you to the tool I think work best for .NET developers: Retire.js.
Retire.js is an excellent "little" tool developed by Erlend Oftedal. It includes a large repository of known vulnerabilities, maintained by the community. It comes in different forms but is essentially a CLI that you run in your project directory.
To install Retire.js, you will need to have npm installed. This comes with Node, so go ahead and install the latest distribution if you haven't already. Then run the install script:
npm install -g retire
This will install Retire.js as a global tool and add it to your PATH. To demonstrate the features of Retire.js, I have created a new ASP.NET Core MVC project and targeted it against ASP.NET Core 3.1. You should never have to create new projects based on old .NET Core versions like this, but I know that doing so will install some vulnerable JavaScript libraries. Once created, we can run Retire.js from the command line in the root of the project:
C:\projects\WebsiteWithVulnerabilities\Website>retire
retire.js v5.2.5
Loading from cache: https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository-v4.json
C:\projects\WebsiteWithVulnerabilities\Website\wwwroot\lib\jquery-validation\dist\additional-methods.js
↳ jquery-validation 1.17.0
jquery-validation 1.17.0 has known vulnerabilities: severity: high; summary: Regular Expression Denial of Service vulnerability, CVE: CVE-2021-21252, githubID: GHSA-jxwx-85vp-gvwm; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1193--2021-01-09 severity: low; summary: ReDoS vulnerability in URL2 validation, CVE: CVE-2021-43306, issue: 2428, githubID: GHSA-j9m2-h2pv-wvph; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1194--2022-05-19 severity: high; summary: ReDoS vulnerability in url and URL2 validation, CVE: CVE-2022-31147, githubID: GHSA-ffmh-x56j-9rc3; https://github.com/advisories/GHSA-ffmh-x56j-9rc3 https://github.com/jquery-validation/jquery-validation/commit/5bbd80d27fc6b607d2f7f106c89522051a9fb0dd severity: medium; summary: Potential XSS via showLabel, PR: 2462; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1200--2023-10-10
C:\projects\WebsiteWithVulnerabilities\Website\wwwroot\lib\jquery-validation\dist\additional-methods.min.js
↳ jquery-validation 1.17.0
jquery-validation 1.17.0 has known vulnerabilities: severity: high; summary: Regular Expression Denial of Service vulnerability, CVE: CVE-2021-21252, githubID: GHSA-jxwx-85vp-gvwm; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1193--2021-01-09 severity: low; summary: ReDoS vulnerability in URL2 validation, CVE: CVE-2021-43306, issue: 2428, githubID: GHSA-j9m2-h2pv-wvph; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1194--2022-05-19 severity: high; summary: ReDoS vulnerability in url and URL2 validation, CVE: CVE-2022-31147, githubID: GHSA-ffmh-x56j-9rc3; https://github.com/advisories/GHSA-ffmh-x56j-9rc3 https://github.com/jquery-validation/jquery-validation/commit/5bbd80d27fc6b607d2f7f106c89522051a9fb0dd severity: medium; summary: Potential XSS via showLabel, PR: 2462; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1200--2023-10-10
C:\projects\WebsiteWithVulnerabilities\Website\wwwroot\lib\jquery-validation\dist\jquery.validate.js
↳ jquery-validation 1.17.0
jquery-validation 1.17.0 has known vulnerabilities: severity: high; summary: Regular Expression Denial of Service vulnerability, CVE: CVE-2021-21252, githubID: GHSA-jxwx-85vp-gvwm; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1193--2021-01-09 severity: low; summary: ReDoS vulnerability in URL2 validation, CVE: CVE-2021-43306, issue: 2428, githubID: GHSA-j9m2-h2pv-wvph; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1194--2022-05-19 severity: high; summary: ReDoS vulnerability in url and URL2 validation, CVE: CVE-2022-31147, githubID: GHSA-ffmh-x56j-9rc3; https://github.com/advisories/GHSA-ffmh-x56j-9rc3 https://github.com/jquery-validation/jquery-validation/commit/5bbd80d27fc6b607d2f7f106c89522051a9fb0dd severity: medium; summary: Potential XSS via showLabel, PR: 2462; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1200--2023-10-10
C:\projects\WebsiteWithVulnerabilities\Website\wwwroot\lib\jquery-validation\dist\jquery.validate.min.js
↳ jquery-validation 1.17.0
jquery-validation 1.17.0 has known vulnerabilities: severity: high; summary: Regular Expression Denial of Service vulnerability, CVE: CVE-2021-21252, githubID: GHSA-jxwx-85vp-gvwm; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1193--2021-01-09 severity: low; summary: ReDoS vulnerability in URL2 validation, CVE: CVE-2021-43306, issue: 2428, githubID: GHSA-j9m2-h2pv-wvph; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1194--2022-05-19 severity: high; summary: ReDoS vulnerability in url and URL2 validation, CVE: CVE-2022-31147, githubID: GHSA-ffmh-x56j-9rc3; https://github.com/advisories/GHSA-ffmh-x56j-9rc3 https://github.com/jquery-validation/jquery-validation/commit/5bbd80d27fc6b607d2f7f106c89522051a9fb0dd severity: medium; summary: Potential XSS via showLabel, PR: 2462; https://github.com/jquery-validation/jquery-validation/blob/master/changelog.md#1200--2023-10-10
C:\projects\WebsiteWithVulnerabilities\Website\wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.js
↳ bootstrap 4.3.1
bootstrap 4.3.1 has known vulnerabilities: severity: medium; summary: Bootstrap Cross-Site Scripting (XSS) vulnerability, CVE: CVE-2024-6531, githubID: GHSA-vc8w-jr9v-vj7f; https://github.com/advisories/GHSA-vc8w-jr9v-vj7f https://nvd.nist.gov/vuln/detail/CVE-2024-6531 https://github.com/rubysec/ruby-advisory-db/blob/master/gems/bootstrap/CVE-2024-6531.yml https://github.com/twbs/bootstrap https://www.herodevs.com/vulnerability-directory/cve-2024-6531
C:\projects\WebsiteWithVulnerabilities\Website\wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.min.js
↳ bootstrap 4.3.1
bootstrap 4.3.1 has known vulnerabilities: severity: medium; summary: Bootstrap Cross-Site Scripting (XSS) vulnerability, CVE: CVE-2024-6531, githubID: GHSA-vc8w-jr9v-vj7f; https://github.com/advisories/GHSA-vc8w-jr9v-vj7f https://nvd.nist.gov/vuln/detail/CVE-2024-6531 https://github.com/rubysec/ruby-advisory-db/blob/master/gems/bootstrap/CVE-2024-6531.yml https://github.com/twbs/bootstrap https://www.herodevs.com/vulnerability-directory/cve-2024-6531
C:\projects\WebsiteWithVulnerabilities\Website\wwwroot\lib\bootstrap\dist\js\bootstrap.js
↳ bootstrap 4.3.1
bootstrap 4.3.1 has known vulnerabilities: severity: medium; summary: Bootstrap Cross-Site Scripting (XSS) vulnerability, CVE: CVE-2024-6531, githubID: GHSA-vc8w-jr9v-vj7f; https://github.com/advisories/GHSA-vc8w-jr9v-vj7f https://nvd.nist.gov/vuln/detail/CVE-2024-6531 https://github.com/rubysec/ruby-advisory-db/blob/master/gems/bootstrap/CVE-2024-6531.yml https://github.com/twbs/bootstrap https://www.herodevs.com/vulnerability-directory/cve-2024-6531
C:\projects\WebsiteWithVulnerabilities\Website\wwwroot\lib\bootstrap\dist\js\bootstrap.min.js
↳ bootstrap 4.3.1
bootstrap 4.3.1 has known vulnerabilities: severity: medium; summary: Bootstrap Cross-Site Scripting (XSS) vulnerability, CVE: CVE-2024-6531, githubID: GHSA-vc8w-jr9v-vj7f; https://github.com/advisories/GHSA-vc8w-jr9v-vj7f https://nvd.nist.gov/vuln/detail/CVE-2024-6531 https://github.com/rubysec/ruby-advisory-db/blob/master/gems/bootstrap/CVE-2024-6531.yml https://github.com/twbs/bootstrap https://www.herodevs.com/vulnerability-directory/cve-2024-6531
As shown from the output, our project includes old versions of jQuery and Bootstrap with known vulnerabilities. Every listing contains a message as well as useful links to pages where you can get additional details, like this one: https://github.com/advisories/GHSA-vc8w-jr9v-vj7f. Running this will give you a good overview of the state of your current JavaScript dependencies and whether anything needs an upgrade.
There are many possibilities with the CLI that I don't want to go further into in this post. To see the possibilities, you can run Retire.js with an --help
option:
C:\projects\WebsiteWithVulnerabilities\Website>retire --help
Usage: cli [options]
Options:
-V, --version output the version number
-v, --verbose Show identified files (by default only vulnerable files are shown)
-c, --nocache Don't use local cache
--jspath <path> Folder to scan for javascript files (deprecated)
--path <path> Folder to scan for javascript files
--jsrepo <path|url> Local or internal version of repo. Can be multiple comma separated. Default: 'central')
--cachedir <path> Path to use for local cache instead of /tmp/.retire-cache
--proxy <url> Proxy url (http://some.host:8080)
--outputformat <format> Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx, cyclonedxJSON and
cyclonedxJSON1_6
--outputpath <path> File to which output should be written
--ignore <paths> Comma delimited list of paths to ignore
--ignorefile <path> Custom ignore file, defaults to .retireignore / .retireignore.json
--severity <level> Specify the bug severity level from which the process fails. Allowed levels none, low,
medium, high, critical. Default: none
--exitwith <code> Custom exit code (default: 13) when vulnerabilities are found
--colors Enable color output (console output only)
--insecure Enable fetching remote jsrepo/noderepo files from hosts using an insecure or self-signed SSL
(TLS) certificate
--ext <extensions> Comma separated list of file extensions for JavaScript files. The default is "js"
--cacert <path> Use the specified certificate file to verify the peer used for fetching remote
jsrepo/noderepo files
--includeOsv Include OSV advisories in the output
--deep Deep scan (slower and experimental)
-h, --help display help for command
One parameter that I want to mention is --colors
which includes severity-based colors on the output. This is a nice addition when running the tool locally.
Having to run Retire.js manually is doomed to be forgotten over time. Automation is the way forward, which is what we have done on elmah.io too. I wanted us to run Retire.js as part of our builds on Azure DevOps. This can easily be done by running the CLI as part of the build pipeline, but I wanted an even easier approach. That's why I set out to develop a small extension for Azure DevOps that will run Retire.js with the right parameters and output parsing. The extension is made available for free in the Azure DevOps Marketplace here: https://marketplace.visualstudio.com/items?itemName=elmahio.retire-extension.
Let's set up a build pipeline for our vulnerable website:
trigger:
- master
pool:
vmImage: windows-latest
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '9.0.x'
installationPath: $(Agent.ToolsDirectory)/dotnet
- task: DotNetCoreCLI@2
displayName: Build
inputs:
command: 'build'
Next, click the Get it free button on the Azure Marketplace listing:

This will redirect you to the install page, where you can pick where to install the extension:

After clicking the Install button, the Retire.js extension is available for you to use in your build pipeline. The extension works in both the old UI-based builds as well as in YAML. To run Retire.js as part of our build, we can extend the pipeline with the following code:
- task: Retire@1
inputs:
verbose: false
failOnVulnerabilities: false
I have included two out of three available inputs for the task. The third is a custom path
parameter which I haven't included in this example. verbose
translates directly to the parameter of the same name in Retire.js. As suggested by the name, it outputs some additional information about each vulnerability. failOnVulnerabilities
is unique to the extension and will cause the Azure DevOps build to fail if any vulnerabilities are found.
When running the pipeline, you will see output like this:

Notice how each vulnerability is listed as a warning in the build output, alongside a formatted output of each vulnerability. This is one of the advantages of using the extension over running the retire
command manually using a script
task or similar.
With this pipeline in place, we can start automating the process of detecting vulnerabilities in our JavaScript dependencies. I hope this post has inspired some of you to start looking at your dependencies too.
elmah.io: Error logging and Uptime Monitoring for your web apps
This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.
See how we can help you monitor your website for crashes Monitor your website