TL;DR: Legacy Java remains embedded in enterprise systems, with nearly 70% of organisations saying more than half of their applications run on Java or the JVM, according to Azul's 2025 survey cited by Oligo Security. Runtime protection shifts the focus from static vulnerability lists to live execution paths, which is where legacy library abuse actually becomes exploitable.
At a glance
What this is: This is an analysis of Java runtime defense for legacy libraries, arguing that live execution monitoring matters more than static vulnerability lists when unpatchable dependencies stay in production.
Why it matters: It matters because teams responsible for application, workload, and identity-adjacent security need controls that see what code is actually executing, not just what might be reachable.
By the numbers:
- Only 5.7% of organisations have full visibility into their service accounts, according to the Ultimate Guide to NHIs.
Context
Legacy Java risk is a governance problem as much as a technical one. Many enterprise systems still depend on libraries that are hard to patch, hard to replace, or no longer maintained, which leaves security teams relying on assumptions about what code is safe rather than evidence from production execution.
The article’s core claim is that build-time tools cannot reliably show the runtime truth of Java applications. For teams managing application security, workload identity, and production resilience, the question is no longer whether a dependency exists but whether it is actively executing in a way that can be abused.
That makes runtime defense a practical control boundary for legacy estates. Instead of treating every disclosed flaw as equally exploitable, teams need to understand which code paths are live, which unsafe flows are reachable, and where blocking can happen without breaking business processes.
Key questions
Q: What breaks when legacy Java libraries are only assessed at build time?
A: Build-time assessment misses the runtime context that determines whether a vulnerable library is actually reachable. That creates blind spots around dormant versus active code, especially in legacy applications where only a small subset of functions may execute. The result is false confidence, noisy prioritisation, and delayed containment of the paths attackers can really abuse.
Q: Why do unpatchable Java dependencies create ongoing risk in production apps?
A: They remain live inside business-critical workflows even after a fix is unavailable or too disruptive to apply. If the vulnerable code is still executed, the risk persists because exploitability depends on runtime reachability, not whether a CVE has been documented. That is why compensating controls matter when architectural replacement is slow.
Q: How do security teams tell whether a legacy Java flaw is actually exploitable?
A: They need to trace the full execution path from input to sink and confirm that the vulnerable method is both loaded and invoked in production. A flaw that exists in code but never runs is not immediately exploitable. Runtime observation is the practical test because it shows whether the attack chain can actually form.
Q: Should teams replace static scanning with runtime protection for Java applications?
A: No. Static scanning still helps inventory risk, but it cannot tell you which paths are live or whether an exploit chain is active. Runtime protection is the better containment layer when patching is delayed, because it blocks unsafe behavior in production while the organisation modernises legacy dependencies.
Technical breakdown
Why build-time analysis misses legacy Java runtime risk
Static analysis tells teams what might exist in the codebase, but not what is actually executing in production. In legacy Java estates, that distinction is critical because many libraries are present in dependency trees yet never invoked on the paths that matter. Runtime truth means observing function-level execution, so security teams can separate theoretical exposure from active exposure. The technical gap is not visibility in the abstract, but the mismatch between compilation-time assumptions and live application behavior. Practical implication: teams should base prioritisation on observed runtime execution, not on presence alone.
Practical implication: Prioritise live execution data over static reachability reports when deciding which Java libraries create immediate risk.
How unsafe execution flows become exploitable
Vulnerable Java code is often exploitable only when a specific execution chain is present. A deserialization flaw, JNDI lookup, unsafe XML handling, or file access issue may be harmless in one workflow and dangerous in another if attacker-controlled input reaches it. The article’s key technical point is that presence of a vulnerable method is not enough; exploitability depends on runtime context, inputs, and reachable sinks. That is why runtime protection focuses on blocking unsafe function calls and anomalous behaviors as they occur. Practical implication: map vulnerable components to the exact execution paths that can turn them into real attack surfaces.
Practical implication: Trace exploitability from input to sink, then monitor the live paths that can turn a library flaw into an actual compromise.
Why blocking at runtime can preserve business continuity
The operational challenge in legacy Java is that immediate remediation is often not feasible. Refactoring or replacing a core library can break business logic, so teams defer change even when they know a vulnerability exists. Runtime defense changes the control model by preventing malicious actions at the function level while leaving ordinary execution intact. That makes it a compensating control rather than a replacement for patching. The article also emphasises telemetry, so teams can see what was blocked and what remains active. Practical implication: use runtime blocking to reduce exposure while modernization and dependency cleanup proceed in parallel.
Practical implication: Deploy runtime containment where patching is delayed, and use the resulting telemetry to plan dependency remediation without interrupting services.
Threat narrative
Attacker objective: The objective is to convert a reachable Java runtime flaw into active execution or unsafe application behavior that can be used for compromise.
- Entry begins when an attacker reaches a legacy Java application through an exposed execution path such as an API endpoint handling unsafe input.
- Credential access is not the main mechanism here; the abuse comes from triggering vulnerable runtime behavior in libraries that are already loaded and active.
- Escalation occurs when that unsafe behavior is chained into command execution, filesystem access, or other privileged application actions inside the runtime.
- Impact follows when the attacker turns the application into a vehicle for code execution, data access, or broader compromise without needing the dependency to be newly installed.
Breaches seen in the wild
- Commvault Metallic breach 2025: A nation-state actor exploited a Commvault zero-day in Azure and may have taken app secrets that open customers' Microsoft 365 tenants.
- United Nations breach 2021: Sakura Samurai used exposed Git credentials to reach 100,000+ UNEP staff records, then reported the flaw through the UN disclosure programme.
Read and download The State of NHI & AI Agent Breach Report 2026, covering 200+ breaches impacting Non-Human Identities including AI Agents.
NHI Mgmt Group analysis
Runtime truth is now the decisive control variable for legacy Java. Static inventories and build-time scanners cannot tell teams whether a vulnerable library is actually executed in production, which is the difference between theoretical exposure and exploitable exposure. That gap matters most in legacy estates where dependencies remain embedded for years. Practitioners should treat observed execution as the governance boundary, not package presence.
Legacy Java creates a false patchability assumption. Security programmes often behave as if disclosed vulnerabilities will eventually be remediated in place, but the article shows that many libraries have no maintainer, no fix, or too much architectural coupling to replace quickly. That means the control problem is not just patch management, it is compensating for structural immobility. Teams need governance that accepts unpatchable code as an operational reality rather than an exception.
Live blocking changes the risk equation for production apps. Runtime defense does not solve legacy debt, but it narrows the window in which unsafe execution can be abused while preserving service continuity. That is the right model for business-critical systems where full replacement is not immediate. Security leaders should view runtime blocking as a containment layer that buys time without pretending modernization is complete.
Transitive dependency risk is the hidden blind spot in Java estates. The article’s emphasis on deep library chains reflects a broader programme issue: teams can govern only what they can inventory and observe. When vulnerable packages sit several layers down, the real risk is not just the library itself but the inability to explain where it is active. The practical conclusion is that runtime visibility and dependency governance must be joined, not treated as separate controls.
Legacy Java security is shifting from prevention at build time to control at execution time. That is a material change in how application risk should be framed. The decisive question is no longer whether a flaw exists in the artifact, but whether the runtime can prove and constrain its use in production. Practitioners should align their controls to execution evidence, because that is where modern exploitation actually happens.
From our research library:
- 96% of security operations teams report critical blind spots, most commonly in cloud infrastructure (74%) and identity and access behaviour (67%).
- Read next: Identity Visibility and Intelligence Platforms (IVIP) Guide
What this signals
Runtime visibility is the new control plane for legacy Java. Teams cannot govern what they cannot see, and build-time analysis is too detached from production behaviour to support confident remediation sequencing. The practical shift is toward runtime evidence, where active paths and dormant dependencies are separated before effort is spent.
Dependency governance now has to account for transitive risk. Legacy Java applications often inherit exposure through deep library chains that are invisible to ordinary review processes. That means the programme question is not just whether a package is approved, but whether its execution is observable when the application is live.
For teams looking to reduce alert fatigue, runtime containment can change the signal quality of legacy Java operations. By narrowing attention to actually executing code, practitioners can focus security work on the small subset of flows that are both live and exploitable.
For practitioners
- Instrument production execution paths Use runtime telemetry to identify which Java classes and methods are actually executed in business-critical applications, then separate active code from dormant dependency noise.
- Prioritise exploitable library paths Map vulnerable libraries to the exact runtime flows that can reach deserialization, JNDI, file access, or command execution sinks before deciding what needs containment.
- Contain unsafe behavior without service disruption Block malicious function-level actions in legacy Java while preserving ordinary transactions, especially where refactoring would create unacceptable business interruption.
- Reduce dependency remediation debt Use runtime observations to decide which legacy libraries need modernization first, rather than treating every disclosed CVE as equally urgent.
- Feed runtime findings into security operations Route block events and execution history into SecOps workflows so teams can tune containment rules and validate which mitigations are actually reducing exposure.
Key takeaways
- Legacy Java risk is driven by what actually executes in production, not by what appears in a build-time inventory.
- Runtime defense matters because unpatchable or hard-to-replace dependencies can stay live long after static tools have flagged them.
- The most effective control shift is from theoretical vulnerability management to live containment and execution-aware prioritisation.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
MITRE ATT&CK addresses the attack and risk surface, while NIST CSF 2.0 and CIS Controls v8 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| MITRE ATT&CK | TA0006; TA0008; TA0040 — Credential Access; Lateral Movement; Impact | The article describes exploit paths that turn runtime abuse into compromise and impact. |
| Recommendation — Map vulnerable Java execution paths to attacker tactics and hunt for runtime abuse, privilege escalation, and impact chains. | ||
| NIST CSF 2.0 | PR.AA-05 — Access Permissions, Entitlements and Authorizations | Runtime blocking and execution-aware control depend on limiting what code paths can do. |
| Recommendation — Align runtime enforcement with access entitlements so only verified execution paths can reach sensitive actions. | ||
| CIS Controls v8 | CIS-5 — Account Management | Legacy application risk here is tied to controlling what identities and services can execute unsafe actions. |
| Recommendation — Inventory application-facing identities and revoke any unnecessary privileges that expand Java runtime blast radius. | ||
Key terms
- Runtime Defense: Runtime defense is the set of controls that inspect, constrain, and stop unsafe AI behavior while the system is operating. For hospitality deployments, it covers both incoming prompts and outgoing responses, plus the tool calls that agents may trigger after a model decides to act.
- Runtime Reach: The total set of identities, repositories, tools, memory paths, and services an autonomous system can actually access while executing a task. It is broader than the workflow that was originally approved, and it determines the real governance boundary for agent behaviour.
- Transitive Dependency: A transitive dependency is a package that your software uses indirectly through another library rather than calling it directly. These dependencies often hide in Java estates, which makes visibility and runtime validation necessary to understand what code is actually present and active.
- Execution Path: An execution path is the chain of systems, roles, functions, and permissions that an identity uses to reach a target service. For AI agents, this matters more than the label on the agent itself because effective authority often comes from the path, not the object.
Deepen your knowledge
NHI governance, agentic AI identity, and machine identity lifecycle are core topics in our NHI Foundation Level course, the industry's only accredited NHI security programme. If you are building or maturing an IAM programme, it is worth exploring.
Published by the NHIMG editorial team on May 15, 2026.
Updated on October 8, 2026.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org