Security Baked Into the JVM: why fork Apache River and OpenJDK?
The more distributed a system, the harder it is to secure.<br>Code crosses JVM boundaries.<br>Objects are serialized across trust boundaries.<br>Third-party proxies run inside your process.<br>The usual answer is a network firewall. It helps, but it operates at the wrong level.
Java 17 deprecated the SecurityManager, Java 24 put the final nail in its coffin.<br>Most developers didn’t notice.<br>Applications that load and execute remote code did: the JVM no longer has a built-in mechanism to restrict what that code can do.
The SecurityManager removal forced a rethink of the whole security architecture from scratch.<br>That turned out to be an opportunity.<br>The authorization problem and the service-discovery problem are separate.<br>Each has a dedicated project.<br>They are designed to be used together.
DirtyChai : a community fork of OpenJDK that restores Java’s authorization infrastructure; required to run JGDMS.<br>JGDMS : a security-hardened fork of Apache River, providing dynamically-discoverable microservices over IPv6.
DirtyChai scales vertically. JGDMS scales horizontally.
DirtyChai adds virtual thread support and a lock-free policy engine to a single JVM.<br>JGDMS makes a fleet of those JVMs discoverable, self-registering, and self-healing.
In this series, I want to explore how the two projects push security into every layer of the platform.<br>Each post covers one layer: from codebase auditing to identity to authorization to performance.
This post focuses on the two projects: what they are, what they are not, and a first taste of deployment.
JGDMS
JGDMS is described in its own project descriptor as:
Infrastructure for providing secured micro services, that are dynamically discoverable and searchable over IPv6 networks.
— JGDMS on GitHub
Most RPC frameworks stop at calling a remote method.<br>JGDMS goes further: services announce themselves on IPv6 networks, clients find them by capability rather than hard-wired address, and trust is established cryptographically before any code runs.<br>Three concepts drive the design:
Jini-model service discovery
lease-based registrations, multicast and unicast lookup, event-driven service notifications.
JERI
a pluggable, constraint-based RPC layer that supersedes standard Java RMI with pluggable transport, per-method security requirements, and authenticated dispatch.
Defence-in-depth security
hardened deserialization, TLSv1.3 transport, Java authorization, proxy trust verification, and a codebase safety pipeline that analyzes third-party bytecode before it is ever loaded.
What JGDMS Is Not
JGDMS is not a sandbox for running untrusted code.<br>It will not safely isolate malicious bytecode.<br>The goal is the opposite: prevent untrusted code from ever being loaded.<br>LoadClassPermission is the gate; SCAP (covered in Part 2) pre-analyzes JARs before any client deserializes an object from them.<br>If you need to run code you don’t trust, you need a different tool.
Running on bare OpenJDK is not supported.<br>On standard OpenJDK ≤ 23, virtual threads get an AccessControlContext with no permissions when SecurityManager is enabled: they simply don’t work in a security context.<br>On OpenJDK 24+, SecurityManager was removed entirely.<br>DirtyChai is the only supported runtime JDK.
Building is a different story.<br>JGDMS is compile-time compatible with standard OpenJDK : you can build with any standard OpenJDK toolchain.<br>DirtyChai is binary compatible with software compiled on OpenJDK, so no recompilation is needed when switching runtimes.
DirtyChai
DirtyChai is a community fork of OpenJDK that restores, improves, and extends Java’s authorization infrastructure:<br>the SecurityManager, AccessController, and ProtectionDomain APIs that OpenJDK deprecated in Java 17 and removed entirely in Java 24.
Without these APIs you cannot restrict what code from a particular source can do once it is loaded.<br>DirtyChai’s goal is not a sandbox.<br>Its goal isn’t to run untrusted code safely, but to ensure trusted but independent parties operate only within their declared and granted privileges.
Feature<br>Source
Prevent loading of untrusted code
LoadClassPermission
Break deserialization gadget attack chains
SerialObjectPermission
Block native code injection
NativeInvocationPermission<br>NativeMemoryPermission
Maintain and extend permission guard hooks
guards
SPIFFE/SPIRE zero-touch certificate management
SpiffeX509TrustManager<br>SpiffeX509KeyManager
A minimal JGDMS deployment
In three steps, we define a remote interface, configure the launcher, and start the service.<br>Pay attention to Step 2 below: authentication, encryption, and hardened deserialization are declared in the deployment configuration and bound to every call by the exporter — never written into the service API.<br>The interface stays a plain Remote interface, so the same service redeploys under different security postures (relaxed in dev, mutual TLS in production) without touching a line of code.<br>A call...