Java is one of the most used programming languages in the industry. It is employed for a wide spectrum of applications ranging from GUIs and databases to server, web, and mobile applications and IoT software. Java has the advantage of being platform-independent, making it possible to run the same Java application on all standard platforms such as Windows, Linux or macOS.
Java belongs to the group of memory-safe language as it is equipped with runtime error detection for array bounds and pointer dereferences. This protects against memory-related issues such as buffer overflows and dangling pointers. As a result, many developers tend to be under the misapprehension that using Java automatically leads to creating secure applications. Even though many types of pitfalls of C/C++ (memory management, pointer arithmetic) are unproblematic in Java, other types of security vulnerabilities are omnipresent in Java applications. This includes SQL injection, insecure deserialization, cross-site scripting, etc. These vulnerabilities are mainly a result of the incorrect handling of user data.
The most effective way to uncover vulnerabilities in the code that relates to user-controlled input is fuzzing. This effective technique has been rather difficult to set up for most developers without security experience. CI Fuzz with its simple IDE integration and automated setup of fuzz tests now makes fuzzing Java applications possible.
With release 2.0, our testing solution now includes Java and JVM Support.
Here are the new features included in CI Fuzz 2.0:
CI Fuzz brings the power and efficiency of in-process fuzzing as done by libFuzzer into Java. This is achieved by creating fuzz targets that can be run by libFuzzer. These targets, along with their dependencies, are instrumented so that the Java code that is reached during fuzzing is reported back to the libFuzzer driver. This allows leveraging the power of libFuzzer to mutate the inputs in order to maximize code coverage.
This process can be integrated into standard CI/CD workflows, thus allowing for continuous testing during the development process. Moreover, this makes it possible to leverage the ability to implement custom mutators for libFuzzer. We leverage this to perform structure-aware fuzzing for Java programs that expect inputs of a certain structure, which enables the fuzzer to find deep bugs in the business logic of the program and not only the input parsing part.
CI Fuzz strives to provide a usable solution and thus does not require any changes to the build system used for the project. Users only need to provide the JAR files generated by the build system and the corresponding dependencies.
Our solution can be effectively used to detect a wide range of vulnerabilities in Java code: any type of unhandled exceptions, e.g., Runtime Exceptions: NullPointerExceptions, ArrayIndexOutOfBounds Exception, BufferOverflow Exception, NumberFormatException, and ParseException when reading user data. Unhandled exceptions might crash the applications, which opens the door to denial of service (DoS) attacks.
CI Fuzz can also be used to perform functional tests that are a valuable addition to normal unit tests. In the fuzz target, developers can define invariants that must be maintained under all circumstances. For example, compressing data, uncompressing results, and finally compressing again should always result in the same original data. The fuzzer then will explore the program state by generating inputs that maximize code coverage and report those inputs where the invariants are violated. This is exceptionally important since fuzzers are very good at uncovering corner cases that developers forget or do not consider.
Finally, we are currently working on adding checks to detect further types of critical vulnerabilities including injections and cross-site scripting.
See our Java fuzzing solution in action