Application Security

Java Module System Security Features: What JPMS Actually Delivers

The Java Platform Module System promised stronger encapsulation and security boundaries. Here is what it actually delivers and where the gaps remain.

Bob
Application Security Lead
5 min read

When Java 9 introduced the Java Platform Module System (JPMS), it was pitched as a way to bring stronger encapsulation to the platform. Internal APIs that everyone had been using through reflection -- things like sun.misc.Unsafe -- would finally be locked down. Modules would declare explicit dependencies and exports, creating clear boundaries between components.

Five years later, the reality is more nuanced than the marketing. JPMS does provide genuine security benefits, but it also has significant limitations that developers need to understand.

What JPMS Actually Provides

Strong Encapsulation

Before JPMS, any class on the classpath could access any other class through reflection, regardless of visibility modifiers. This meant that private and package-private access controls were suggestions, not enforcement. Libraries routinely reached into the internals of other libraries (and the JDK itself) using setAccessible(true).

JPMS changes this. A module must explicitly export packages that other modules can access. Non-exported packages are truly inaccessible from outside the module, even through reflection. This is enforced at the JVM level, not just at compile time.

This matters for security because it prevents one module from tampering with the internal state of another. A malicious or compromised dependency cannot use reflection to access private fields in your security-critical code if those packages are not exported.

Reliable Configuration

JPMS requires modules to declare their dependencies explicitly in module-info.java. The module system verifies at startup that all required dependencies are present and that there are no split packages (the same package provided by multiple modules). This catches configuration errors early rather than at runtime.

From a security perspective, reliable configuration means that a missing or substituted dependency is detected at application startup rather than failing unpredictably at runtime. This makes it harder for an attacker to exploit configuration confusion.

Services and ServiceLoader

JPMS integrates with the ServiceLoader mechanism to provide a controlled way for modules to discover and use implementations of service interfaces. The provides and uses directives in module-info.java make service dependencies explicit and auditable.

Where JPMS Falls Short on Security

The Classpath Escape Hatch

JPMS is optional. Any application can continue to run entirely on the classpath, where modules are treated as unnamed modules with full access to everything. In practice, many applications still use the classpath because migrating to modules requires effort and can break compatibility with libraries that rely on reflective access.

The --add-opens and --add-exports flags allow applications to punch holes in module encapsulation at startup. Many frameworks (Spring, Hibernate, and others) require these flags to function. Every --add-opens flag is a hole in the security boundary that JPMS is supposed to provide.

Reflection Is Still Powerful

While JPMS restricts reflective access to non-exported packages, modules can still grant deep reflection access using the opens directive. A module that declares opens com.example.internal to framework.module allows that framework full reflective access to the internal package.

In practice, many modules are forced to open their internals to frameworks that require reflection. This significantly reduces the security value of module encapsulation.

No Integrity Verification

JPMS does not verify the integrity or authenticity of modules. There is no built-in mechanism to ensure that a module has not been tampered with or that it comes from a trusted source. Module loading relies on the classpath or module path, and whatever JAR file is found first wins.

This means JPMS does not protect against supply chain attacks where a malicious JAR file is substituted for a legitimate one. You need separate mechanisms (like JAR signing, checksum verification, or SCA tools) to verify module integrity.

No Runtime Isolation

JPMS modules all run in the same JVM process. A compromised module has full access to the JVM, including the ability to call System.exit(), allocate unlimited memory, or spawn threads. Module boundaries are access control boundaries, not security isolation boundaries.

For true isolation, you need separate JVM processes, containers, or other OS-level isolation mechanisms. JPMS is not a substitute for defense in depth.

Practical Security Recommendations

Migrate to modules when feasible. The encapsulation benefits are real, even if imperfect. Modules make your application structure explicit and auditable, which is valuable for security review.

Minimize --add-opens flags. Every --add-opens is a security compromise. Audit the flags your application requires and investigate whether newer versions of frameworks have reduced their reflective access needs.

Use module-info.java as a security review artifact. The exports, opens, requires, and uses directives in module-info.java provide a concise summary of a module dependencies and exposed surface area. Include these in security reviews.

Do not rely on JPMS for supply chain security. JPMS provides encapsulation, not integrity. You still need SCA tools, dependency verification, and SBOM generation to protect against supply chain attacks.

Combine JPMS with SecurityManager (where possible). While SecurityManager is deprecated for removal, in environments where it is still available, it provides additional runtime restrictions that complement JPMS encapsulation.

How Safeguard.sh Helps

Safeguard.sh provides comprehensive Java dependency analysis that works alongside JPMS. We scan your module declarations, identify exposed surface area, track vulnerabilities in both direct and transitive dependencies, and generate SBOMs that include module-level metadata. Our platform helps you verify the integrity of your Java supply chain -- the piece that JPMS itself does not address.

Never miss an update

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