You can't patch what you can't find: building a real JVM inventory

Most enterprises can't say how many JVMs they run or where. Here's what a useful JVM inventory captures, how to collect it, and where it goes wrong.
Patchmageddon Team

Patchmageddon Team

JVM patching & OpenJDK migration specialists

·6 min read

Ask a platform team how many Java runtimes the company runs and you'll usually get a confident number. Ask where that number came from and the confidence drops. It's typically the CMDB, a vulnerability scanner report, or a spreadsheet someone built during the last Log4j scramble.

None of those is wrong, exactly. They're incomplete in ways nobody can measure. That's the problem, because every later step (patching, upgrades, license decisions, audit responses) depends on the list being right.

Why nobody has an accurate list

JVMs don't only show up as "a Java application we deployed." They arrive in several other ways, and most of those skip the processes that would record them.

Shadow JVMs inside vendor products

Commercial software often ships its own private Java runtime. Databases, monitoring tools, backup agents, BI platforms, network management consoles and security products regularly bundle a JRE in their install directory. It isn't on the PATH, it doesn't show up in the OS package manager, and the team that installed the product often doesn't know it's there.

These runtimes tend to be the oldest in the estate, because they're only updated when the vendor ships a new release. We cover how to handle them in patching JVMs inside vendor products.

Application servers

Tomcat, WebLogic, WebSphere and JBoss/WildFly installations usually point at a specific JDK through a startup script or environment file, not the system default. A server can have a patched JDK installed next to it while still running an old one.

Containers

Every container image that includes Java carries its own runtime, fixed at build time. Patching the host changes nothing inside the container. When a base image is rebuilt rarely, or a team copied an old FROM line years ago, the vulnerable runtime ships to production on every deploy.

Build agents and desktop tools

CI runners, build agents, developer workstations and desktop tools such as IDEs, database clients and internal Swing apps all carry JVMs too. They're often left out of scope because "they're not production." They still count toward license exposure, and build agents are an attractive target for attackers.

What a useful inventory captures

A list of hostnames with "Java: yes" doesn't help much. To drive decisions, each record needs:

FieldWhy it matters
Every running instance, across dev, staging and prodNon-production environments still count for licensing and are still attack surface
Version, vendor/distribution and patch levelOracle JDK vs. Temurin vs. Corretto vs. Zulu changes both licensing and the patch source
Where it's embeddedStandalone app, app server, vendor product, or container image, since each is patched a different way
CVE exposure, scored per JVMA risk score per runtime, adjusted for exposure (such as internet-facing), not just a raw CVE count
OwnerThe person or team who can approve a change. Often the hardest field to fill in
Installed agentsAPM, security and profiling Java agents are a leading cause of patch failures
Criticality signalEnough to seed a proper risk classification later

The last two fields are often skipped, and they're what turn an inventory into a patch plan. Knowing a JVM runs an APM agent tells you to test that agent before rollout. A criticality signal tells you which process the app should go through (see our approach).

How to collect it

No single source is complete. The reliable approach combines several and reconciles them.

Agentless host scanning

Over SSH (Linux/Unix) or WinRM (Windows), with a read-only account, you can:

  • List running processes and capture the full path of each java executable
  • Search the filesystem for Java installations, including ones that aren't running
  • Read each installation's release file, which most modern JDKs and JREs include and which records the version and implementor

Here is a simple, read-only example for a Linux host:

# Running JVMs: resolve the actual binary behind each java process
for pid in $(pgrep -x java); do
  bin=$(readlink -f "/proc/$pid/exe" 2>/dev/null)
  echo "running pid=$pid bin=$bin"
done

# Installed JVMs: find 'release' files next to a bin/java, then print key fields
find / -xdev -type f -name release -path '*/release' 2>/dev/null |
while read -r f; do
  dir=$(dirname "$f")
  [ -x "$dir/bin/java" ] || continue
  echo "== $dir"
  grep -E '^(JAVA_VERSION|IMPLEMENTOR|JAVA_RUNTIME_VERSION)=' "$f"
done

Older runtimes, Java 8 and earlier in particular, may not have a release file or may record fewer fields. For those, running "$dir/bin/java" -version is the fallback. It executes the binary, so decide deliberately whether your access policy allows that.

The script above only lists and reads. A production discovery tool also has to handle multiple filesystems, container overlay mounts, Windows registry entries and installers that rename directories.

CMDB and configuration-management reconciliation

Compare what you found with what your CMDB and your Ansible, Puppet or Chef data say should be there. The differences are often as valuable as the inventory itself: runtimes nobody registered, records for servers decommissioned years ago, and hosts where configuration management thinks it installed JDK 17 but something else is actually running.

Cloud provider APIs

AWS, Azure and GCP APIs list instances, managed container services and serverless functions, along with tags that often point to an owner or cost center. Serverless runtimes managed by the provider are a different conversation, but you still need to know they exist.

Container image scanning

Scan the images in your registries and the images actually running in your clusters. Registry scanning finds what could be deployed. Cluster scanning finds what is deployed, including images from registries nobody remembers configuring.

Artifact repository scanning

Nexus and Artifactory hold the build outputs that become deployments. Scanning them finds embedded runtimes, such as a bundled JRE inside a distribution archive, before they're running anywhere.

Reuse what your scanners already know

If you run a general-purpose vulnerability scanner, it has already seen many of these hosts. Use its data as an input rather than competing with it. What it usually can't do is interpret the results for Java specifically: which runtime a finding belongs to, whether it's embedded in a vendor product, what the patch path is, and what the licensing implication is.

What the output looks like

To make that concrete, here's an illustrative example, not a real client result. A mid-sized estate assessment might report:

  • 340 JVMs discovered, of which 118 were missing from the CMDB
  • 60 past end of public support
  • 12 with critical CVEs open for more than 400 days, several on internet-facing hosts
  • 38 Oracle JDK installations, which under Oracle's employee-based subscription can bring the whole headcount into license scope (see the employee metric explained)

Numbers like these do what a policy memo can't: they give security, platform and finance a shared, specific reason to act.

Where discovery goes wrong

Ephemeral workloads

Autoscaling groups, short-lived containers and batch jobs make "inventory" a moving target. A point-in-time scan will miss some of them. Decide early whether you're counting instances, images or both. Scanning images and deployment definitions usually gives a more stable picture than chasing instances.

Ownership needs people

Scanning can tell you what's running. It rarely tells you who's accountable for it. Tags, CMDB records and cost centers get you part of the way. The rest takes interviews and follow-up, so budget time for it instead of assuming it can be automated.

Access and data handling

Getting even read-only access across a fragmented estate is a procurement and security exercise in its own right. Ask for the minimum privilege that works, document exactly what's collected, and agree up front on data retention and handling. This matters most in regulated environments.

Discovery is read-only, so it usually doesn't need a change ticket. That makes it the fastest way to start improving a Java estate without first winning a governance argument.

What to do next

If you don't trust your current count, start with a scoped discovery of one business unit and compare it to what your records say. Our JVM discovery and estate assessment does exactly that. Once you have the inventory, drift monitoring keeps it current as the estate changes.

#jvm-inventory#discovery#cmdb#shadow-it#cve-exposure
Patchmageddon Team

Patchmageddon Team

The Patchmageddon team helps enterprises find every JVM in their estate, patch it on a sane cadence, and stop paying for Oracle Java they don't need.

Find out what's actually running in your estate

A Quick Scan inventories the JVMs in one business unit in days. You get versions, vendors, patch levels, CVE exposure and Oracle licensing exposure, with no production changes and no CAB ticket.