A URL is a name, and names get reused. Replace the bytes behind https://repo.example.org/order-processor.jar and every permission granted to that URL still applies, now to code nobody audited. So far in this series, Part 1 declared constraints on a remote call, Part 2 vetted code before a client loaded it, Part 3 established who is calling, and Part 4 carried that chain of identities across the wire.
Introducing composable, module system native and agent friendly command line tools for modern Java developmentBy Danny Thomas, JVM Ecosystem TeamRecent work on the Java language to pave the on-ramp has made it easier than ever to start a Java program and evolve it using the full language and platform. At the end of that on-ramp lies Java’s mature build and dependency management ecosystem, capable of carrying software to enormous scale and complexity.That ecosystem reached its maturity by developing strong models for projects, dependencies, and builds. When the Java Module System arrived,…
Alice calls the order service. The order service calls the ledger on her behalf. At the second hop, the ledger has to decide whose authority the debit is being made under. Most stacks answer badly. Forward Alice’s bearer token verbatim, and the ledger cannot tell her from the service that relayed it. Drop the token and the ledger sees a machine, with no record that a human started the chain. Neither option lets the ledger authorize the combination.
Every engineer has a story about the “harmless” change that wasn’t. This is mine.Ours didn’t start with a bad deploy. No risky feature flag, no sketchy migration, no Friday-evening hotfix. It started with a change every ops playbook calls safe:We gave a struggling service more CPU.We went from 1.5 cores to 2.5 cores. That’s it. And within minutes, our lead-creation API — the thing that turns a visitor tapping “Contact” into an actual business lead — stopped creating leads. Entirely across web and app.The twist that cost us hours: the more CPU we threw at it, the worse it got. This is the…
The constraint system stops a bad call before it leaves the JVM. The Safe Codebase Audit Pipeline stops bad code before a client ever loads it. What remains is identity: who is calling, and can you verify it? Most frameworks answer with a token check at the door. A filter validates a bearer token, sets a thread-local variable, and hopes that nothing downstream forgets to look at it. DirtyChai answers differently.
In Part 1, the minimal deployment showed constraints traveling with the proxy: authentication, encryption, hardened deserialization, all declared in configuration and enforced at the call boundary. The proxy is a JAR. That JAR was downloaded and unmarshalled before any constraint ran. That step is the earlier problem. Distributed Java systems that load remote code are vulnerable to supply chain compromise: an attacker can replace a legitimate JAR with one containing malicious bytecode.
The more distributed a system, the harder it is to secure. Code crosses JVM boundaries. Objects are serialized across trust boundaries. Third-party proxies run inside your process. 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. Most developers didn’t notice.
Optional Google Analytics helps us understand visits. Microsoft Clarity records masked interactions to improve the site. Optional tools stay off unless you choose them. Privacy details.