Skip to content

CodeIntelligenceTesting/jazzer.js

 
 

Repository files navigation

Jazzer.js logo

Jazzer.js

NPM GitHub Actions

Jazzer.js is a coverage-guided, in-process fuzzer for the Node.js platform developed by Code Intelligence. It is based on libFuzzer and brings many of its instrumentation-powered mutation features to the JavaScript ecosystem.

Jazzer.js currently supports the following platforms:

  • Linux x86_64
  • macOS x86_64 and arm64

Quickstart

To use Jazzer.js in your own project follow these few simple steps:

  1. Add the @jazzer.js/core dev-dependency

    npm install --save-dev @jazzer.js/core
  2. Create a fuzz target invoking your code

    // file "FuzzTarget.js"
    module.exports.fuzz = function (data /*: Buffer */) {
    	const fuzzerData = data.toString();
    	myAwesomeCode(fuzzerData);
    };
  3. Start the fuzzer using the fuzz target

    npx jazzer FuzzTarget
  4. Enjoy fuzzing!

Usage

Creating a fuzz target

Jazzer.js requires an entry point for the fuzzer, this is commonly referred to as fuzz target. A simple example is shown below.

module.exports.fuzz = function (data) {
	myAwesomeCode(data.toString());
};

A fuzz target module needs to export a function called fuzz, which takes a Buffer parameter and executes the actual code under test.

The Buffer, a subclass of Uint8Array, can be used to create needed parameters for the actual code under test, so that the fuzzer can detect the usage of parts of the input and mutate them in the next iterations to reach new code paths. In this use-case Buffer is not the nicest abstraction to work with and will be replaced with a more suitable one in the future. An example on how to use the data parameter is shown below, documentation on Buffer can be found in the Node.js documentation.

module.exports.fuzz = function (data) {
	const intParam = data.readInt32BE(0);
	const stringParam = data.toString("utf-8", 4);
	myAwesomeCode(intParam, stringParam);
};

Asynchronous fuzz targets

Jazzer.js supports asynchronous fuzz targets out of the box, no special handling or configuration is needed.

The resolution of a Promise returned by a fuzz target is awaited before the next fuzzing input is provided. This enables the fuzzing of async/await, Promise and callback based code.

Asynchronous code needs careful synchronization between the Node.js Event Loop and the fuzzing thread, hence provides a lower throughput compared to synchronous fuzzing. Even so, asynchronous fuzzing is the default mode of Jazzer.js due to its prevalence in the JavaScript ecosystem and because it works for all fuzz targets.

Solely synchronous code can participate in the enhanced performance of synchronous fuzzing by setting the --sync flag when starting the fuzzer.

An example of a Promise based fuzz target can be found at examples/promise/fuzz.js.

Using TypeScript to write fuzz targets

It is also possible to use TypeScript, or in that matter any other language transpiling to JavaScript, to write fuzz targets, as long as a modules exporting a fuzz function is generated.

An example on how to use TypeScript to fuzz a library can be found at examples/js-yaml/package.json.

Running the fuzzer

After adding @jazzer.js/core as dev-dependency to a project the fuzzer can be executed using the jazzer npm command. To do so use npx:

npx jazzer <fuzzer parameters>

Or add a new script to your package.json:

"scripts": {
"fuzz": "jazzer <fuzzer parameters>"
}

The general command format is:

jazzer <fuzzTarget> <fuzzerFlags> [corpus...] [-- <fuzzingEngineFlags>]

Detailed documentation and some example calls are available using the --help flag, so that only the most important ones are discussed here.

Parameter Description
<fuzzTarget> Import path to the fuzz target module.
[corpus...] Paths to the corpus directories. If not given, no initial seeds are used nor interesting inputs saved.
-- <fuzzingEngineFlags> Parameters after -- are forwarded to the internal fuzzing engine (libFuzzer). Available settings can be found in its options documentation.
-i, --instrumentation_includes / -e, --instrumentation_excludes Part of filepath names to include/exclude in the instrumentation. A tailing / should be used to include directories and prevent confusion with filenames. * can be used to include all files. Can be specified multiple times. Default will include everything outside the node_modules directory.
--sync Enables synchronous fuzzing. **

May only be used for entirely synchronous code**. | | --help | Detailed help message containing all flags. |

Documentation

Further documentation is available at docs/readme.md.

Credit

Jazzer.js is inspired by its namesake Jazzer, also developed by Code Intelligence.

Code Intelligence logo