Safeguard
Developer Tools•

Fuzzing Java and Kotlin with Jazzer and JUnit

Jazzer is a coverage-guided fuzzer for the JVM. Add a FuzzTest method, run in regression mode by default, and switch fuzzing on when you want a hunt.

Safeguard Security Team
3 min read

Jazzer is an in-process, coverage-guided fuzzer for the JVM, built on libFuzzer. You can write a JUnit method with the FuzzTest annotation. By default it replays saved crashing inputs as a normal unit test, and an environment variable switches it into real fuzzing mode.

Why JVM code needs fuzzing

Memory corruption is rare in Java, but parsers still throw unexpected exceptions, loop forever, or exhaust memory on crafted input. Jazzer also ships bug detectors for risky behavior. Its README names Server-Side Request Forgery, file path traversal and OS command injection among them, so it can flag dangerous behavior and not only crashes.

Two ways to write a target

From the Jazzer README, with a JUnit test:

@FuzzTest
void parseDoesNotThrow(String input) {
    Parser.parse(input);
}

Jazzer generates and mutates inputs for the method parameters, which can be primitives, strings, arrays and many standard library types. The standalone alternative is a class with a public static method named fuzzerTestOneInput whose parameters match what you want to feed.

Uncaught exceptions count as failures, and a crashing input is saved to the inputs directory.

Two run modes

  • Regression mode (the default): replays saved crashing inputs as a unit test. Set JAZZER_COVERAGE=1 to include generated corpus inputs.
  • Fuzzing mode: set JAZZER_FUZZ=1, for example JAZZER_FUZZ=1 mvn test with your test class named.

This split is a good fit for build pipelines. Every normal build checks that old bugs stay fixed, quickly. A separate scheduled job turns fuzzing on and hunts for new ones.

Setup

Maven and Gradle projects add the jazzer-junit artifact, and the README states it needs JUnit 5.9.0 or newer. You can also run from the command line with the Jazzer binary or by launching the Jazzer main class with your target class. Double dash flags are Jazzer options and single dash flags are libFuzzer options. If the JVM library is not found, make sure JAVA_HOME points to a JDK.

Choosing what counts as a bug

If your parser documents that it throws a checked exception on bad input, catch that in the test. Everything else, a NullPointerException, an ArrayIndexOutOfBounds, a StackOverflowError, is worth a look. Bug detectors can be turned off with the disabled hooks setting if one is noisy for your code.

Kotlin and other JVM languages

Jazzer works on bytecode, so Kotlin and other JVM languages are handled the same way as Java. The README describes it as bringing libFuzzer style mutation to Java, Kotlin and other JVM languages. Write the test in whichever language your project uses.

Tips

  1. Keep the target fast. Avoid network and file access.
  2. Use small seed files for formats like XML or JSON.
  3. Run for a bounded time in CI.
  4. Commit crashing inputs so regression mode keeps checking them.

Quick check

Does a JUnit fuzz test run forever in my normal build?

No. By default it runs in regression mode, replaying saved inputs. Fuzzing starts only when you set the fuzz environment variable.

Can Jazzer find security issues beyond crashes?

It has bug detectors for classes such as SSRF, path traversal and command injection. Check the README for the current list, since it changes.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.