What it is: Direct Use of Unsafe JNI (CWE-111) is a weakness where a Java application calls native code via the Java Native Interface, inheriting that native code's weaknesses even though they can't occur in pure Java.
Why it matters: Native code operates outside the JVM's memory-safety guarantees, so a buffer overflow or similar bug in the native library becomes directly reachable from the Java application.
How to fix it: Only use native libraries from a trusted, reviewed source, validate all input crossing the JNI boundary, and prefer a pure-Java equivalent API when one exists.
TL;DR: CWE-111 exposes a Java application to native-code weaknesses (like buffer overflows) that can’t occur in managed Java, because JNI calls run outside the JVM’s memory-safety guarantees; the fix is trusted, reviewed native libraries plus strict input validation at the JNI boundary.
| Field | Value |
|---|---|
| CWE ID | CWE-111 |
| OWASP Category | Not directly mapped |
| CAPEC | None known |
| Typical Severity | High |
| Affected Technologies | Java applications using the Java Native Interface (JNI) |
| Detection Difficulty | Moderate |
| Last Updated | 2026-07-27 |
What is Direct Use of Unsafe JNI?
Direct Use of Unsafe JNI (CWE-111) is a weakness that occurs when a Java application uses the Java Native Interface (JNI) to call code written in another programming language, exposing the application to weaknesses in that code, even if those weaknesses cannot occur in Java itself. As defined by the MITRE Corporation under CWE-111, this weakness has no official OWASP Top 10:2025 category mapping and is a direct child of Use of Low-Level Functionality (CWE-695) and Improper Input Validation (CWE-20).
Quick Summary
Java’s memory-safety guarantees are one of the platform’s core security properties — no buffer overflows, no use-after-free, no manual pointer arithmetic gone wrong. JNI is the one deliberate escape hatch from all of that: code called through it runs as real native machine code, with none of those protections, and whatever weaknesses exist in that native library are now reachable from inside an otherwise “safe” Java application.
Jump to: Quick Summary · Direct Use of Unsafe JNI Overview · How Direct Use of Unsafe JNI Works · Business Impact of Direct Use of Unsafe JNI · Direct Use of Unsafe JNI Attack Scenario · How to Detect Direct Use of Unsafe JNI · How to Fix Direct Use of Unsafe JNI · Framework-Specific Fixes for Direct Use of Unsafe JNI · How to Ask AI to Check Your Code for Direct Use of Unsafe JNI · Direct Use of Unsafe JNI Best Practices Checklist · Direct Use of Unsafe JNI FAQ · Vulnerabilities Related to Direct Use of Unsafe JNI · References · Scan Your Own Site
Direct Use of Unsafe JNI Overview
What: A Java application calls native code (typically C/C++) through JNI, inheriting whatever weaknesses that native code has.
Why it matters: Native code operates outside the JVM’s memory-safety protections, so bugs there can have consequences (like buffer overflows) that are essentially impossible in pure Java.
Where it occurs: Java applications that load native libraries via System.loadLibrary()/System.load() and declare native methods calling into them.
Who is affected: Java applications using JNI to call untrusted, unvetted, or unmaintained native libraries.
Who is NOT affected: Java applications with no JNI usage, or that only call thoroughly-reviewed, trusted native libraries with careful boundary input validation.
How Direct Use of Unsafe JNI Works
Root Cause
The Java application calls a native library through JNI without sufficiently validating that the library is trustworthy or that input crossing the JNI boundary is properly checked.
Attack Flow
- The application loads a native library via JNI to perform some task (e.g. fast image processing, hardware access).
- That native library has a memory-safety bug (e.g. a buffer overflow) triggerable by attacker-influenced input.
- The Java application passes attacker-controlled data across the JNI boundary into the native function.
- The native code’s bug is triggered, potentially corrupting memory, crashing the process, or in a worst case, enabling code execution.
Prerequisites to Exploit
- The Java application loads and calls a native library via JNI.
- That native library has an exploitable weakness (e.g. missing bounds checking).
- Attacker-influenced input reaches the vulnerable native function through the JNI call.
Vulnerable Code
public class ImageProcessor {
static {
System.loadLibrary("legacy_image_lib");
}
public native void resize(byte[] imageData, int width, int height);
}
The application loads and calls an unvetted native library directly with attacker-influenced image data and dimensions, with no validation of the library’s provenance or the input’s bounds before it crosses into native code.
Secure Code
public class ImageProcessor {
private static final int MAX_DIMENSION = 8192;
static {
System.loadLibrary("legacy_image_lib"); // sourced from a reviewed, trusted release
}
public native void resize(byte[] imageData, int width, int height);
public void resizeSafely(byte[] imageData, int width, int height) {
if (imageData == null || imageData.length == 0) {
throw new IllegalArgumentException("Invalid image data");
}
if (width <= 0 || width > MAX_DIMENSION || height <= 0 || height > MAX_DIMENSION) {
throw new IllegalArgumentException("Invalid dimensions");
}
resize(imageData, width, height);
}
}
The native library is sourced from a reviewed, trusted release, and a Java-side wrapper validates both the data and dimensions before anything crosses the JNI boundary, reducing the chance of triggering an unchecked bug in the native code.
Business Impact of Direct Use of Unsafe JNI
Access Control: MITRE notes this weakness’s consequence as Bypass Protection Mechanism — Java’s own memory-safety guarantees are bypassed entirely for the native portion of the call.
- Memory corruption or crashes triggerable through attacker-influenced input reaching native code
- In the worst case, native memory-safety bugs (buffer overflows) can enable code execution outside Java’s normal security model entirely
Direct Use of Unsafe JNI Attack Scenario
- An application uses an old, unmaintained native image-processing library via JNI for performance reasons.
- An attacker uploads a crafted image with dimensions engineered to trigger a known buffer overflow in that native library.
- The Java application passes the attacker’s data directly into the native
resize()call with no bounds validation. - The native library’s buffer overflow is triggered, corrupting memory in ways Java’s own runtime would never have allowed, potentially crashing the process or worse.
How to Detect Direct Use of Unsafe JNI
Manual Testing
- Search the codebase for
nativemethod declarations andSystem.loadLibrary()/System.load()calls. - Identify which native libraries are loaded and confirm their source and security review status.
- Trace whether attacker-influenced input reaches any native call without validation.
Automated Scanners (SAST / DAST)
Static analysis can flag native method declarations and library-loading calls directly in source, while a manual review of the linked native library’s own code (if available) is typically needed to assess its actual safety, since dynamic testing of compiled native code is a separate discipline from standard Java DAST.
PenScan Detection
PenScan’s scanner engines flag Java applications that load and call native libraries via JNI, particularly libraries with no clear trusted provenance.
False Positive Guidance
A JNI call to a well-known, actively-maintained, and widely-reviewed native library (with a strong security track record) carries meaningfully lower risk than one to an obscure or unmaintained library — weigh the specific library’s provenance, not just the presence of JNI usage, before treating this as a high-priority finding.
How to Fix Direct Use of Unsafe JNI
- Only use native libraries from a trusted source, ideally with reviewed source code or a strong security maintenance track record.
- Validate all input (content and length) crossing the JNI boundary before it reaches native code.
- Wrap JNI calls with error handling to fail safely rather than propagating undefined native-side behavior.
- Prefer a pure-Java equivalent API over a native library when one exists, removing JNI from the equation entirely.
Framework-Specific Fixes for Direct Use of Unsafe JNI
This weakness is specific to Java’s JNI mechanism; it has no equivalent in languages without a comparable native-interop boundary, so no forced-fit examples are given for non-JVM stacks.
- Java: validate all data crossing the JNI boundary, source native libraries only from trusted, reviewed releases, and prefer pure-Java APIs where available, as shown above.
How to Ask AI to Check Your Code for Direct Use of Unsafe JNI
Review the following Java code block for potential CWE-111 Direct Use of Unsafe JNI vulnerabilities and rewrite it to validate all data crossing the JNI boundary before it reaches native code: [paste code here]
Direct Use of Unsafe JNI Best Practices Checklist
✅ Only use native libraries from a trusted, reviewed source ✅ Validate all input crossing the JNI boundary for content and length ✅ Wrap JNI calls with error handling ✅ Prefer a pure-Java equivalent API when one exists
Direct Use of Unsafe JNI FAQ
How does JNI expose a Java application to weaknesses Java itself doesn’t have?
Java’s managed runtime protects against memory-corruption bugs like buffer overflows, but code called through JNI runs as native machine code with no such protection, so a buffer overflow or similar memory-safety bug in that native library becomes directly reachable from the Java application.
How is this different from a normal third-party library risk?
A vulnerable pure-Java dependency is still contained by the JVM’s memory safety guarantees; a vulnerable native library reached via JNI operates entirely outside those guarantees, so its bugs can corrupt memory, crash the process, or in the worst case enable code execution in ways a pure-Java bug class typically cannot.
How do I detect this in my own application?
Search the codebase for “native” method declarations and System.loadLibrary()/System.load() calls, then identify which native libraries are loaded and whether their provenance and security history have actually been reviewed.
How do I fix this without abandoning a needed native library?
Validate all input crossing the JNI boundary for content and length before it reaches native code, wrap JNI calls with error handling, and only use native libraries from a trusted source whose code has been reviewed or that comes with a track record of security maintenance.
How does input validation at the JNI boundary help specifically?
Since native code often lacks the bounds-checking Java provides automatically, validating length and content on the Java side before a value crosses into native code is one of the few controls available to reduce (though not eliminate) the risk of triggering a native memory-safety bug.
How can a Java-only equivalent avoid this risk entirely?
If a pure-Java API exists that performs the same function as the native library, using it removes JNI from the equation entirely, along with every native-code weakness class that comes with it.
How can PenScan help find this weakness?
PenScan flags Java applications that load and call native libraries via JNI, particularly libraries with no clear trusted provenance.
Vulnerabilities Related to Direct Use of Unsafe JNI
| CWE | Name | Relationship |
|---|---|---|
| CWE-695 | Use of Low-Level Functionality | ChildOf |
| CWE-20 | Improper Input Validation | ChildOf |
References
Scan Your Own Site
Manual code review catches what you know to look for. An automated scan catches what you didn’t. Scan your own website using PenScan to find unsafe JNI usage and other risks before an attacker does.