Most teams scan their container images on a schedule. A CronJob runs Trivy every few hours, or a pipeline scans on build. That works, but it leaves a blind spot: the time between when a package becomes known-vulnerable and when your next scan of a given image actually runs.
Say a critical CVE lands in openssl 3.0.11. One of your images gets scanned this afternoon and the finding shows up. But you are running the same openssl 3.0.11 in eleven other images, and those are not scheduled to scan again until tomorrow night. For a full cycle, you are exposed in eleven places and your tooling is telling you about one.
Ephor closes that window. Here is how.
The SBOM you already have
When the Ephor scanner runs, it does two things with every image. It scans for vulnerabilities, and it generates a Software Bill of Materials — the full list of packages and versions inside the image. The vulnerabilities you act on. The SBOM usually gets filed away and forgotten.
Ephor keeps it. Every package from every SBOM goes into an index: name, version, license, the image it came from. On its own that is useful for the obvious question — "which images ship log4j?" — the kind of thing you scramble to answer the morning a big CVE drops.
But the more interesting thing is what happens when you cross it with the vulnerabilities you have already found.
Matching known CVEs against the whole fleet
Every vulnerability Ephor records is tied to a specific package and version: this CVE affects openssl 3.0.11. The SBOM index records the same shape of fact: this image contains openssl 3.0.11. So the join is direct. For every known CRITICAL or HIGH finding, Ephor looks for images whose SBOM carries that exact package and version but which have not been flagged for it yet.
vulnerability: openssl 3.0.11 -> CVE-2025-0001 (CRITICAL)
sbom index: redis:7.2 contains openssl 3.0.11
api:1.4 contains openssl 3.0.11
worker:2 contains openssl 3.0.11
----------------------------------------
3 images carry it, none triaged for this CVE
Those three images become pre-scan alerts. You see them in the dashboard the moment the SBOMs are in, without waiting for each image's own scan to come around and rediscover the same package independently.
the pre-scan alerts view
Why exact version, and not something cleverer
The first version of this matched on package name alone. It was wrong, and it is worth being honest about why, because it is the kind of mistake that quietly destroys a security tool.
Matching openssl to openssl means an image running the patched 3.0.12 gets flagged for a CVE that only ever affected 3.0.11. Now your alert list is full of things that are already fixed. A triage tool that cries wolf is worse than no tool, because people learn to scroll past it. So the match requires name and exact version. If Ephor flags an image, it is because that image contains the precise package build that was found vulnerable somewhere else in your fleet — not a guess, the same artifact.
The honest limitation: exact-version matching will not catch a different vulnerable version in the same affected range. "Anything below 3.0.12 is vulnerable" is real range logic, and doing it correctly across Debian, RPM, npm, Go modules and the rest means storing per-ecosystem affected ranges. That is on the roadmap. Until it lands, I would rather show you matches that are certainly true than a longer list you cannot trust. Exact version is the version that does not lie.
Where this sits
Pre-scan alerts are one piece of Ephor, the open-source vulnerability management layer for Kubernetes — the dashboard, triage, and remediation tracking that sit on top of Trivy once the scanning is done. Self-hosted, AGPL, your data stays in your own database. I wrote about why that gap exists, and why I got tired of filling it with a spreadsheet, in The $100K Gap.
The code is on GitHub, the scanner at holbein-io/ephor-scanner. If you run Kubernetes and you have ever found out about a vulnerable image a day later than you would have liked, I would genuinely like to hear whether this helps. Open an issue, or email hello@holbein.io.