Picture the scan of an image your team has shipped for a year. It comes back long, and the instinct is to work down it: open each finding, read the advisory, decide what to do.
Look at where the findings live before you start. Most belong to operating system packages the base image brought with it, packages nobody on your team chose. Most of the rest belong to a handful of application dependencies pinned behind versions that already fix them. Work through the list one finding at a time and the next build brings the same findings back.
This article follows that image through two changes, a new base and a new version for each package, and then through what happens to the findings those two changes cannot reach. It ends with what keeps the result from drifting back.
Two levers move most of a scan result
Changing the base and the pins changes the result; triaging the findings one by one does not. Vulnetix works each lever from its own end. Container curation starts with the image and reads it layer by layer until it finds what the image was built on. Safe Harbour starts with the packages and reads every version each one has published.
A third input decides the order. An image that runs in production deserves the first hour of your week; an image nobody deploys can wait.
- The base image: Container curation reads the layers of each image, finds the base it was built from, and compares that base with the equivalent images Docker Hardened Images, Chainguard, Red Hat and other registries publish: the same runtime, libc and distribution release, ranked by what each one removes.
- The packages: Safe Harbour walks every published version of a package and clears the ones with no known vulnerability, exploit or malware report. The dependency curator applies one policy across a whole manifest; the container migration pins the packages your own layers install to versions the new base release ships.
- Where it runs: A connected AWS account lists every image EKS, ECS, Lambda and ECR hold or run, so each recommendation sits beside the placement it changes and an image nobody deploys does not jump the queue.
Every claim links to something you can check
Back to the image. Its base is a public image, and several registries publish an equivalent with the same runtime, libc and distribution release. Container curation lines them up and ranks them by what each one removes.
A ranked list is easy to produce and hard to trust, so each alternative arrives with what stands behind it: the vulnerabilities it still has, the ones it removes, where the image came from and who signed it. When a vendor's own claim leaves out a vulnerability Vulnetix found in the same image, the comparison shows the gap instead of smoothing it over.
- Advisories: Every vulnerability id links to its record in the Vulnetix database, with the exploit and known-exploited evidence that decides its urgency.
- The registry: Each alternative links to the registry page it came from and the digest its tag resolved to when it was read.
- Signed SBOMs and claims: The vendor signature, the signed SBOM and the vendor vulnerability claim are published through the Transparency Exchange API, with the trust anchors to verify them.
- Independent checks: Copyable commands for cosign, Grype, Trivy and the Vulnetix CLI, so the result is checked with tools you already run rather than taken on trust.
- The gap: When a vendor claim omits a vulnerability Vulnetix found in the same image, the page says so and links each omitted id.
Pick how far each package moves
With a base picked, the packages your own layers install still need versions, and so do the manifests in the repository. Safe Harbour clears every published version that has no known vulnerability, exploit or malware report. Which cleared version you take depends on how far you are willing to move, so you choose a policy and it applies to every package at once.
Safest
The highest stable release that Safe Harbour clears.
Stable
The stable release closest to the one you run.
Latest
The highest stable release by the ecosystem's own version rules.
Rolling
What shipped most recently, closest to the one you run.
A container migration adds a fifth pick, parity: the version the new release ships that is nearest to the one running now. Every pick comes from versions Safe Harbour clears, worked out with the ecosystem's own version rules; a package with no clean version is shown as such and never pinned to a guess.
Rolling has a window: the newest release day, one release day earlier, or one release earlier by version order, for a team that wants a release to age before it takes it.
Where no registry knows a package, such as a Go module hosted on GitHub or an npm dependency that points at a repository, Safe Harbour reads the project's GitHub releases and checks them the same way. A package with no versions anywhere can be kept as it is or given a version by hand, and when a project has no lockfile you choose the package manager and one is generated with your picks.
The change is written, not described
A recommendation that ends in a task list tends to sit in a backlog. This one ends in files. Once the base and the versions are chosen, Vulnetix writes everything the repository needs to build the new image, and you review it like any other change.
- A Dockerfile: FROM pinned by digest, a dev stage when the target ships no shell, and install lines in the package manager's own pin syntax under the policy you chose.
- Your manifests: package.json, requirements.txt, go.mod, Cargo.toml, pom.xml, composer.json and Gemfile edited as text, with transitive fixes written in the override section each ecosystem uses.
- Generated lockfiles: Lockfiles are generated from the edited manifests with install scripts switched off, shown read only, and never edited by hand.
- Local setup: The registry login, a .env, compose and devcontainer overrides, a CI login step and a Renovate rule, so the new base keeps working after the first build.
- A pull request: Opened or updated through the GitHub App, with the checks that read your manifests listed first; or the files to download when the app is not installed.
Autofix from the scanner you already run
Not every fix needs a console. When the problem is the application's dependencies, the scan you already run in CI can make the change. Add --fix to a Vulnetix CLI scan and the vulnerable dependencies it finds are upgraded in place. Your project's own package manager makes the change, and the scan runs again to prove the finding is gone.
The policies from chapter 03 apply here as well, so a developer's laptop and the CI job pick the same versions.
- On every scanner command:
--fix(or--sca-autofix) works onvulnetix scan,sca,sast,secrets,iacandcontainers, so the CI job you already have can fix as well as report.vulnetix autofixruns the fix on its own. - A target you choose:
--fix-strategypicks the Safe Harbour policy: safest, stable, latest or rolling.vulnetix fix --max-major-bumprefuses a target that crosses more major versions than you allow, and--manifestkeeps the edit to one file. - Look before it changes anything:
vulnetix fix --dry-runprints the plan: each package, its current version, the target, and whether it will be fixed or needs a person. - Nothing skipped quietly: A package with no vulnerability-free version is reported and attested as risk-accepted, so the gap is on record instead of missing from the output.
- VEX for every fix: Each applied fix is recorded as CycloneDX VEX, so the next scan, and anyone you share the SBOM with, knows why the finding closed.
- One rule for the organisation:
vulnetix configsets the default strategy and the largest major bump for every repository, so a developer's--fixfollows the same policy as CI.
Software composition analysis · Safe Harbour versions · Dependency curator · Quality gate
For a container, the fix is a new base
Upgrading packages inside an image that starts from a vulnerable base works for one release. The next base update brings the findings back and the work repeats.
The migration plan moves the image to the hardened base you chose in chapter 02 instead, and writes the change for the repository that builds it. From the plan, one button opens the pull request.
- The base, pinned by digest: The
FROMline names the hardened equivalent you picked, by digest, with a dev stage added when the new base ships no shell. - Your own layers too: The packages your Dockerfile installs are pinned in the package manager's own syntax, under the same Safe Harbour policy as your manifests.
- It keeps building: The registry login, a CI login step, compose and devcontainer overrides and a Renovate rule come with the plan, so the second build works like the first.
- Every claim can be checked: Each recommendation links to its vulnerability records, its Transparency Exchange records and the commands that verify the image yourself.
Container scanning · Safe patching · Announcing Safe Harbour
Built where, running where
All of this depends on knowing which Dockerfile built the image you are looking at. In a large estate that is not always obvious: images are retagged and pushed from pipelines nobody has opened in months.
A migration is only as good as what it knows about the image. Vulnetix reads it from the image, from the Dockerfile in CI and from your cloud account, pairs a running image with the file that built it, and says how it made the pairing.
The image
vulnetix image records an image's packages layer by layer, so the plan knows what your own layers add on top of the base.
The Dockerfile
vulnetix containers in CI records each FROM and install line, so an image is listed and planned from the file that builds it before any SBOM exists.
Where it runs
A connected AWS account lists every image EKS, ECS, Lambda and ECR hold or run, and each placement links to the AWS console.
Built and run, together
A running image is paired with the Dockerfile that built it from its source label, the commit in its tag, or its repository's name when the FROM line agrees with the base it resolved to. The page says which.
An agent makes the change, and you approve it
Some fixes are more than a version bump. A new major version removes an API the code calls, or a hardened base ships no shell and a build step needs rewriting.
Agentic Fix hands that work to an agent: from a Pix button beside the finding, or from the Software Factory across every repository you connect. The agent writes the change and opens the pull request; a person decides what merges. The pull request button in chapter 06 is one of these buttons, and the session it starts is shown here.
- A Pix button where the finding is: Upgrade a package to its Safe Harbour pick, work through a scan's upgrades, move a repository off an end of life release, remove a malicious package, fix a blocked install, or open a container migration's pull request. Each button writes the request and names the repository; you press Start.
- Find out why before fixing: Other buttons ask Pix why a run failed, why a build was blocked, or why the checks failed on a pull request. Pix reads the failing logs and says whether the change caused it or the base branch fails too.
- The Software Factory at scale: Crews of agents take findings, issues and failing builds from the board to verified pull requests. Quality gates are plain rules, and anything that needs a person waits in Needs you.
- Where it runs: Sessions run on a Pix Sandbox or a machine you connect, with the Package Firewall in front of every install the agent makes.
- In your own coding agent: The Vulnetix plugin's
fixskill takes a triaged vulnerability to a version bump, the affected code inlined as first-party, a patch or a workaround;verify-fixchecks it landed andvex-publishrecords why it closed.
Software Factory · Vulnetix AI · Pix Sandbox · Announcing the Software Factory · The Pix plugin
A virtual patch for the fix that cannot ship this week
Sometimes the right change is known and still cannot ship: a release freeze, a vendor appliance, a migration that needs a test cycle first.
Between a public exploit and the deployed fix, the only thing in front of the vulnerability is what you can load at the edge. Vulnetix builds blocking rules from the exploits themselves, in the formats your edge and sensors already take.
Formats: Snort, Suricata, ModSecurity, nginx, AWS WAF, Cloudflare WAF, Layer 7 regex.
- Built from the exploit: Every proof of concept published for a vulnerability is collected, and the Vulnetix Team reads each one to find where the attack can be caught. That answer decides the format; an exploit that admits none is recorded as admitting none.
- Written for the tool: An AWS WAF rule is a single WAFv2 Rule that merges into your WebACL, ModSecurity rules sit in an id range that cannot shadow the Core Rule Set, and a layer 7 pattern is checked so hostile input cannot make it a denial of service.
- Safe to start: Every rule states the mode it is safe to start in and what it does not cover, including the evasions it would not survive.
- Deployed like your other rules: Curate rules into a feed, publish it, and point the sensor or pipeline at its URL; it fetches the file with a checksum beside it.
Countermeasures for the attacks the edge cannot see
Many exploits leave nothing on the wire and act only on the device, so a firewall rule has nothing to match. For those, Vulnetix builds detection content from the same exploits, for your SIEM, your EDR and your threat platform.
Formats: Sigma, YARA, STIX 2.1, OpenIOC.
- Sigma for the SIEM: Every search identifier the logic names is declared, so the rule converts to a query that matches.
- YARA for the endpoint and memory: Every string a condition references is declared, because one missing string stops the whole file compiling.
- STIX 2.1 and OpenIOC: A bundle your threat platform imports with the vulnerability, indicators and relationships intact, and a document for a host sweep with real artifact terms.
- The same feeds: Countermeasures publish to feeds like virtual patches do, so the detection side and the blocking side of one vulnerability ship together.
Keep the image clean once it has moved
A hardened base and clean pins drift back if nothing guards them. The next install pulls a newer version, a forgotten pipeline keeps building the old image, or a package you cleared is reported as malware a month later. These are the controls that hold the result, each with the page that covers it.
Block what would undo it
The Package Firewall refuses vulnerable, malicious and untested versions at install time across 25+ registries, so a clean pin is not swapped out on the next build.
Fail the build that regresses
The quality gate fails CI on the severity, malware, exploit and end-of-life policy your organisation sets, with one vulnetix scan command.
Hold the release that drifts
Jails fail a pipeline when findings sit past their remediation window, a runtime goes end of life or a migration misses its date.
Catch malware in what stays
Malware scanning checks the dependencies installed on disk, including the ones your layers add on top of the new base.
Publish the evidence
Signed SBOMs and VEX go to your Transparency Exchange catalogue, so anyone you share it with can check the result of the move.
Your image, not a vendor rebuild
Go back to the image from the start of this article. A hardened registry would rebuild the open source image under it and hand you its artifact. That rebuild is one of the sources Vulnetix compares. The migration starts from the image you already run: it keeps your layers, swaps the base for the best equivalent across every registry we read, pins what you install, and shows the evidence for each step.
When keeping the current base is the better call, the recommendation says keep. When the base is unknown, because the image was squashed or built from a reference we cannot resolve, the page says that too, rather than guessing.
Images arrive three ways: the Vulnetix CLI records an image's packages layer by layer, the Dockerfile scanner records each FROM and install line in a repository, and a connected AWS account lists what EKS, ECS, Lambda and ECR hold or run. Manifests arrive through the GitHub App or an upload. Read more about container scanning and the dependency curator.