Designing CVE Mirrors for Air-Gapped Networks — How an 11-Day-Stale Mirror Created Quiet False Confidence
For SCA and dependency scanning to mean anything in air-gapped networks, you need to maintain CVE / OSV / vendor advisory data internally. Four data streams, four sync traps, one verification.
Last December, in a customer's security review meeting, it took me two minutes to formulate a sentence:
"Our SCA reports clean — but how old is the data?"
The answer was eleven days. Our air-gapped CVE mirror had last synced eleven days earlier. In those eleven days, seven high-severity CVEs had been published, two of which affected our dependency tree. The SCA's "clean" report was correct — for eleven-day-old data.
We rebuilt the entire CVE mirror design after that meeting. This post is the result.
Why a CVE mirror is load-bearing infrastructure in air-gapped networks
In air-gapped environments, SCA, container scanners, and IaC linters all receive their CVE data from an internal mirror. A stale mirror means tools report clean using stale data. The tools aren't lying — the mirror makes them lie.
The trustworthiness of an air-gapped security tool is determined less by the tool itself than by the freshness of the data feeding it.
Four data streams
A CVE mirror isn't one database. It's four data flows.
1. NVD / CVE.org — official CVE IDs + CPE mappings
2. OSV (Google) — per-package open-source advisories + affected ranges
3. Vendor advisories — RedHat / Debian / Ubuntu / Alpine / internal package backports
4. Internal tracker — *your own* fixes / mitigations / accepted risksIf these four don't align, the same vulnerability shows up in different statuses across different tools.
Four sync traps
Trap 1 — sync delay accumulates quietly
If you don't pull NVD's hourly updates every hour, delay accumulates silently. By a week in, you should have an alert; usually nothing fires until day eleven.
Fix: expose the mirror's last sync timestamp as a self-metric; page if it exceeds 24 hours. This one alarm shrinks an eleven-day incident to a one-day one.
Trap 2 — one-way sync's broken pipe
The transit-zone unidirectional gateway fails to deliver files but doesn't return an error. From the gateway's view: quiet success. From your view: data not arriving.
Fix: validate the hash of the last received sync. Every sync must match a checksum; if not, alert. This catches not sync failure but sync fake success.
Trap 3 — vendor advisories speak different languages
RedHat publishes RHSA-XXXX, Ubuntu USN-XXXX, Debian DSA-XXXX. The same CVE surfaces at different IDs at different times across vendors. If your mirror tracks only one vendor, containers built from other vendor OSes pass internal checks and fail external certification.
Fix: explicitly track advisories for every base-image OS in use internally. Usually four to six.
Trap 4 — accepted risk isn't in the mirror
Internal policy may have accepted certain CVEs as known risks. If that decision isn't in the mirror, SCA flags those CVEs every run, operators develop alert fatigue, and they start ignoring real alerts too.
Fix: add the internal risk-accepted tracker as a fifth flow into the mirror. SCA tools recognize it and demote accepted items to informational.
One verification — can a known good CVE be found within a known time
How do you verify the mirror is healthy? Manual inspection isn't an option. We run this verification automatically once a quarter:
1. From NVD, pick five random CVEs *published in the last 24 hours*
2. Confirm all five are in our internal mirror
3. If not — alert + open incident
4. If yes — go one level deeper: do they match our dependency tree?Before this verification existed, "the mirror is fine" was a feeling. With it, we caught four sync delays in three quarters that we would have missed.
Why there isn't more writing on this
Air-gapped CVE mirroring is unglamorous and unprofitable. Global SaaS companies don't have this problem. Public-sector, finance, and defense teams in Korea, Japan, and the EU face it every day. So the English-language material is thin and the Korean-language material is almost nonexistent. Hence this post — a reference for the teams that face this problem every day.
One check to run right now
Security engineers running SCA, container scanners, or IaC linters in an air-gapped environment have one check to run right now — the last mirror sync timestamp. If the answer doesn't come immediately, you've already fallen into at least one of the four traps above.
Related posts
When a Product Manager Ships Code, Who Owns the Outage?
In organizations where product managers write code with AI and several agents work at once, who checks what before a change reaches production? A role design for verification, approval, and recovery that is independent of the author, grounded in NIST SSDF, SLSA provenance, and the Google SRE postmortem culture.
John Baek
An Eclipse Plugin for the Agent Era — Task Context Was Already the Problem 20 Years Ago
The problem Mylyn set out to solve in the mid-2000s is the agent context problem. What changed is that the thing reading that context is no longer only a person.
Yeongsang Kim
A VS Code Extension for the Agent Era — What Developers Look At Now
Once writing code got cheap, a developer's time moved to judging and approving. Here is why those jobs cannot live outside the editor, and the choices behind the CollabOps VS Code extension.
Seungbaek Lee