Skip to content
Norbert Schneider5 min read

Jazzer.js Brings Effective Fuzzing to JavaScript (Open-Source)

TL;DR Fuzzing JavaScript is easy now

In this post, we introduce you to our new open-source fuzzer for the JavaScript ecosystem, Jazzer.js

Jazzer.js is a coverage-guided, in-process fuzzer for the Node.js platform. It’s based on the experience we gathered developing its namesake Jazzer, our fuzzer for the JVM platform. Internally, Jazzer.js uses libFuzzer as a solid industry-standard engine and brings many of its instrumentation-powered mutation features to JavaScript. Even though the initial release is in an early stage of Jazzer.js, it provides comprehensive fuzzing capabilities for your JavaScript and Node.js projects.

MeetJazzer.js

What’s Under the Hood of Jazzer.js?

Besides providing a state-of-the-art fuzzing engine, which is done by integrating libFuzzer as a solid basis, the main goal of Jazzer.js is to seamlessly integrate into the JavaScript development workflow, so that developers can use the tools they know and love for fuzzing.

The libFuzzer integration is realized by a native Node.js add-on, which handles the libFuzzer lifecycle and provides integration and feedback points for the fuzzer’s more high-level JavaScript code. Moreover, libFuzzer’s fuzzing logic is executed in the background and does not interfere with the normal JavaScript execution model. Hence fuzzing of synchronous and asynchronous functions is supported out of the box.

During fuzzing, Jazzer.js instruments loaded code to add coverage feedback mechanisms to it. This enables the fuzzer to detect when new code paths are reached and to further continue in that direction. It also adds feedback mechanisms to detect usage of parts of its fuzzing input, for example, a comparison in an if-statement, to improve the performed mutations and reach even deeper code paths.

What Is libFuzzer?

libFuzzer is a C/C++ fuzzer and part of the LLVM Compiler Infrastructure. It was created by Google to overcome problems with existing fuzzers at the time. It tightly integrates coverage-guided fuzzer logic with available bug detectors, a.k.a. sanitizers. In this setup it provides the basic fuzzing logic, while Jazzer.js bridges the gap between its C/C++ APIs and the JavaScript runtime.

The following diagram shows an overview of the involved components and their interaction.

Jazzer.js-diagram-1How to Fuzz JavaScript

After discussing the fundamentals of Jazzer.js let us now have a look at how to use it in a Node.js JavaScript project. Hence, we assume some familiarity with JavaScript and the Node.js ecosystem.

1. Add Jazzer.js Dependency to the Project

Jazzer.js is bundled as a Node.js package and can be added to projects like any other dependency. Precompiled versions of the native part of the fuzzer are available for all common platforms and downloaded automatically. If a used platform is not available, a dedicated compilation step is executed during installation. To add the Jazzer.js dependency to a Node.js project, execute the following command.

> npm install --save-dev @jazzer.js/core

2. Create a Fuzz Target

Jazzer.js requires an entry point for fuzzing, this is commonly referred to as fuzz target. A simple example of a file-defining one is shown below.

// file: fuzzTarget.js
module.exports.fuzz = function (data) {
myAwesomeCode(data.toString());
};

A fuzz target needs to export a function called fuzz, which takes a Buffer parameter and executes the actual code that should be tested based on the fuzzing input. Please note that the code above is executed in a synchronous fashion. Asynchronous execution is also supported out of the box, as shown in the Jazzer.js promise example.

3. Start Fuzzing

Adding the Jazzer.js dependency to a project also adds the Node.js command jazzer, which can be used to directly start the fuzzer. You can invoke it via npx-specifying the fuzz target created in the last step.

> npx jazzer fuzzTarget
The fuzzer output will look similar to the one below from Jazzer’s string compare example.
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2472745350
INFO: Loaded 1 modules (512 inline 8-bit counters): 512 [0x530fa90, 0x530fc90),
INFO: Loaded 1 PC tables (512 PCs): 512 [0x7fe8bc9a4010,0x7fe8bc9a6010),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 2 ft: 2 corp: 1/1b exec/s: 0 rss: 108Mb
#1331 NEW cov: 5 ft: 5 corp: 2/17b lim: 17 exec/s: 0 rss: 115Mb L: 16/16 MS: 4 CrossOver-InsertByte-ChangeByte-InsertRepeatedBytes-
#5692 NEW cov: 6 ft: 6 corp: 3/33b lim: 58 exec/s: 0 rss: 115Mb L: 16/16 MS: 1 CMP- DE: "Awesome "-
#42739 NEW cov: 7 ft: 7 corp: 4/49b lim: 421 exec/s: 0 rss: 126Mb L: 16/16 MS: 2 ChangeByte-CMP- DE: "Fuzzing"-
==158151== Uncaught Exception: Jazzer.js: Welcome to Awesome Fuzzing!
Error: Welcome to Awesome Fuzzing!
at module.exports.fuzz (/home/norbert/Code-Intelligence/jazzer.js/examples/string_compare/fuzz.js:33:11)
==158151== ERROR: libFuzzer: fuzz target exited
SUMMARY: libFuzzer: fuzz target exited
MS: 1 ChangeByte-; base unit: be159789fe80858724068c1aaa2d5ee7582e3db3
0x41,0x77,0x65,0x73,0x6f,0x6d,0x65,0x20,0x46,0x75,0x7a,0x7a,0x69,0x6e,0x67,0x21,
Awesome Fuzzing!
artifact_prefix='./'; Test unit written to ./crash-dd107abbf60f67c533ff7aecb116ce483fc4facf
Base64: QXdlc29tZSBGdXp6aW5nIQ==
Jazzer.js provides extensive documentation in its source code repository as well as many additional examples.

More Features Coming Soon

There are ideas aplenty. Some of the next effective features that are planned for Jazzer.js are a dedicated hooking framework to enable custom bug detectors, like the ones already very successfully used by Jazzer, e.g. SQL Injections, Remote Code Executions (RCEs), and XSS. Furthermore, Jazzer.js will receive a better test framework integration, to make fuzzing as easy as unit testing. The integration of Jazzer.js into OSS-Fuzz is also planned, with the ultimate goal to ensure continuous security testing for JavaScript components in popular open-source projects.

As you can see, there is great potential in Jazzer.js. Don’t miss any updates by giving the GitHub repository a star and subscribing to our JavaScript newsletter. Lastly, try out Jazzer.js with your own projects. We would love to get your feedback and ideas!

See Jazzer.js on Github



Jazzer.js Live Coding Session

I recently hosted a live coding session where I demonstrated how you can use Jazzer.js to secure your applications against DoS and Uncaught Exceptions. The recording is freely accessible. If you're interested in using Jazzer.js yourself, this will be handy.

Book a Demo with one of our security experts. We will walk you through the product and answer your questions.

Book a Jazzer.js Demo