
Container Vulnerability Scanning: Find Exploitable Risks
Secure cloud-native apps with container vulnerability scanning. Adopt an attacker's perspective to find, prioritize, & fix exploitable risks in Docker &
Container Vulnerability Scanning: Find Exploitable Risks
Secure cloud-native apps with container vulnerability scanning. Adopt an attacker's perspective to find, prioritize, & fix exploitable risks in Docker &
Valiant Team
7/4/202613 min read
Your Scanner Might Be Your Biggest Blind Spot
A lot of teams deploy a scanner and assume they've solved the problem. They haven't. They've added another privileged system to an environment that already contains vulnerable images, and that system often has access to registries, image layers, and deployment workflows.
That matters because attackers target control points, not just workloads. The SentinelOne analysis of container vulnerability scanning tools notes 87% of production container images already harbor high-severity vulnerabilities, and it highlights the "Scanning Tool Supply Chain Poisoning" risk. The same research explains that scanners often require higher-level privileges to access image layers and registries, which makes them attractive targets for attackers trying to inject malicious dependencies or bypass policy.
Think about image scanning and runtime scanning like building security. Image scanning is the pre-occupancy inspection. It checks what you built before people move in. Runtime scanning is the alarm system, camera feed, and guard patrol after the building is live. Attackers care about both because they exploit design flaws before launch and operational mistakes after launch.
What attackers look for first
From an offensive perspective, the first checks are practical:
Scanner privilege: Can the scanning platform read private registries, sign images, or interact with admission controls?
Trust boundaries: Does the scanner run in a segmented environment, or can a compromise pivot into build systems and production clusters?
Policy bypasses: Can engineers override failed scans with a manual approval that nobody reviews?
Stale assumptions: Does the team treat one successful image scan as durable truth, even after the image changes at runtime?
Practical rule: If the scanner can approve what runs in production, secure it like a production secret store, not like a reporting tool.
What doesn't work is treating scanning as a dashboard exercise. What works is assuming the scanner itself sits inside the attack surface and hardening it accordingly.
Understanding Image and Runtime Scanning
Attackers do not care which scanning product a team bought. They care about the gap between what the image looked like in CI and what the container is doing now in production.
Image scanning answers a pre-deployment question. What known vulnerable packages, libraries, secrets, and misconfigurations are baked into the artifact? Runtime scanning answers a live-fire question. Has that container drifted, been misused, or started behaving like an initial foothold?
From an offensive standpoint, both views matter because they fail differently. Image scanning is good at catching inherited debt from the base image and application dependencies. Runtime scanning is good at catching the stuff operators assume away, shell access through an exposed exec path, a dropped binary in a writable directory, a process tree that no longer matches the image, or network activity the build report could never predict.
The Wiz guidance on container vulnerability management highlights the runtime side clearly. It recommends kernel-level visibility through tools such as Falco or eBPF-based detectors so teams can see system calls, process execution, and network connections inside running containers. That is the data attackers generate during exploitation. Static scans will not show a reverse shell, privilege misuse, or post-compromise tooling fetched after deployment.
A concise comparison helps:


The failure mode I see often is over-trusting the image result. A clean image scan only says the scanner did not find a known problem in the artifact it examined. It does not prove the running container still matches that artifact, and it does not tell you whether an attacker can reach and use the vulnerable component.
Sysdig's container image scanning overview makes a useful distinction here. Image scans can miss software that is copied in later, activated only at runtime, or left behind as stray files and packages that confuse inventory. In practice, that means zombie binaries and orphaned packages create two problems at once. They increase noise in the report and give an attacker more tooling than the approved SBOM suggests should exist.
That is why exploitability has to drive priority. If a vulnerable library sits in a layer that never executes, has no reachable attack path, and is absent from the running process tree, it belongs below a lower-CVSS issue tied to an internet-facing service with the right privileges and a known exploit chain.
Package managers are a good example. If a compromised container still has apt, apk, or yum available, the attacker gets an easier post-exploitation path. They can pull tools, modify state, and blend in with admin activity. Image scanning should catch that exposure before release. Runtime monitoring should still alert when those binaries execute, because by then the problem is no longer hygiene. It is active attacker behavior.
The Anatomy of a Modern Scan
Attackers do not care where your scanner runs. They care where your control breaks.
A modern container scan has to test each point where an image can change state, pick up risk, or slip past policy. That starts before the build, continues after the image is assembled, checks what lands in the registry, and verifies what the orchestrator is allowed to run. If you only scan the final image once in CI, you get a snapshot. An attacker gets every gap around that snapshot.
Where to place security gates
Each gate should answer a specific abuse case, not just add another report to the pipeline.
Pre-build dependency review
Review application dependencies, base images, and build instructions before assembly. Through this process, teams catch outdated libraries, risky package sources, and unnecessary tooling that later gives an intruder post-compromise options.
Post-build image scan
Scan the built image as it will ship. Enumerate OS packages, language dependencies, embedded binaries, secrets, and misconfigurations introduced during the build process.
Registry validation
Validate the image again after push. The registry is where provenance, signatures, and deployment eligibility should be enforced, because tags are easy to reuse and easy to trust too much.
Admission control
Check the deployment request before the container starts. This gate should block images that fail policy, lack attestations, or do not match the digest that was approved.
Runtime verification
Confirm that the running container still matches expectations. That includes process execution, file changes, network behavior, loaded libraries, and privilege use.
NIST SP 800-190, Application Container Security Guide supports this layered model. It treats container security as a chain of controls across image creation, registry, orchestration, and runtime rather than a single scanner decision.
What a strong scan validates
A useful scan answers four questions.
Was the image built from approved components?
Did the final artifact contain anything extra?
Did the exact approved digest reach deployment?
Did the running container stay inside that boundary?
That last question matters more than many teams admit. From an offensive perspective, drift is where weak programs get exposed. A side-loaded binary, a debug tool left in a layer, a package manager still present in production, or a startup script changed after approval all create attack paths that a package-only CVE scan will not explain well.
Chainguard's guide to container image verification and signed provenance is useful on this point. Signature verification and provenance checks help confirm that the image being deployed is the image that was built and approved. They do not replace vulnerability scanning, but they close a gap attackers regularly use, especially in environments that trust tags more than digests.
A practical checklist:
Approved SBOM: Keep a versioned SBOM for each production image.
Digest pinning: Approve and deploy by digest, not mutable tags.
Layer inspection: Review every layer for hidden tools, package managers, and stray binaries.
Provenance checks: Require signed build metadata and verify it at deployment.
Runtime comparison: Compare the running container against the approved image and alert on drift.
Teams that skip these checks usually still have dashboards full of findings. They just do not have proof that the thing they scanned is the thing an attacker is operating inside.
Integrating Scanning into Your DevSecOps Pipeline
Security has to move with delivery. If scanning slows every release, teams route around it. If scanning runs only after deployment, the business accepts preventable risk.
The fix is to treat container vulnerability scanning as a release control, not an afterthought.
Early in the pipeline, visualizing the workflow helps align engineering and security teams.


Build a pipeline that blocks bad images early
A practical DevSecOps pattern usually looks like this:
Commit gate: Run dependency checks when code is committed so engineers catch obvious issues before the build queue starts.
Build gate: Scan the built image immediately after assembly. Trivy, Grype, or similar tools are often employed at this stage.
Registry gate: Mark only approved images as deployable. Unsigned or policy-failing images should stay in the registry but never enter production.
Admission gate: Use Kyverno or OPA to prevent deployment of vulnerable or misconfigured containers.
Runtime gate: Monitor live workloads and alert on drift, suspicious execution, or policy violations.
The YouTube discussion on container scanner risk and policy enforcement adds an important operational point. Scanners often need high privileges, which creates compromise risk, so teams should isolate them and use segmentation. That same guidance recommends Kyverno or OPA for enforcement and micro-segmentation plus network policies so workloads don't talk to each other unnecessarily. If a scanner or container is compromised, segmentation limits the blast radius.
Later in the pipeline, this walkthrough is worth sharing with engineering leaders:




Stop ranking risk by CVSS alone
CVSS is useful for labeling severity. It is bad at telling you what an attacker will hit first in your environment.
A better prioritization model combines three questions:



Executive takeaway: The right pipeline doesn't try to fix everything first. It stops the small number of images that create the largest exploitable risk.
When teams rank by CVSS alone, they burn time on theoretical issues while exposed and privileged containers stay in service. The attacker only needs one of those.
Prioritizing Real-World Risk Beyond CVSS Scores
Attackers do not hunt by spreadsheet order. They hunt for the container that turns a working exploit into access, secrets, or lateral movement.
That is why CVSS-only triage fails. It flattens very different situations into the same score and hides the question that matters in an intrusion. Can this bug be used here, on this workload, with these privileges, against something worth reaching
Use runtime context to cut noise
Static scan output gives you inventory. Runtime context tells you where an operator or adversary would spend time. The ARMO discussion of runtime scanning and risk prioritization explains the value clearly. Teams need to separate vulnerabilities that are exploitable in a live container from findings that exist on paper but have no realistic path to execution.
In real triage, I care about four things first:
Execution path: Is the vulnerable library or binary loaded by the application, or is it dead weight in the image?
Reachability: Can an attacker hit it from the internet, from another namespace, or from a compromised internal service?
Privilege after compromise: Does code execution land inside a root container, expose mounted credentials, or inherit a service account with broad rights?
Post-exploit mobility: Can that container reach databases, cloud metadata services, CI workers, or adjacent workloads?
Those answers change the order fast. A medium CVE in a public API container with cloud credentials is usually more urgent than a critical CVE in an isolated batch image that never accepts inbound traffic.
Version control matters here too, but for a different reason than compliance checklists usually stress. If teams deploy floating tags, broad base images, and inconsistent registry sources, analysts waste time proving what is running before they can even test exploitability. The Docker best practices for choosing minimal base images and pinning image versions help reduce that uncertainty. Smaller images remove tools attackers like to use after initial access. Pinned versions make it possible to tie a finding to a specific artifact instead of arguing over what latest meant at deploy time.
If two containers carry the same CVE, fix the one that is reachable, privileged, and connected to sensitive systems first.
Score the container, not just the CVE
A useful prioritization model adds environment facts to the scanner result. I recommend scoring the workload around the vulnerability, not just the vulnerability itself.
Start with the finding, then add:
Exposure
Public entry points, ingress paths, and broad east-west reachability raise the chance of exploitation.
Privilege
Root, added Linux capabilities, host mounts, writable sockets, and inherited cloud permissions increase blast radius.
Asset value
Payment services, identity systems, CI infrastructure, and data stores deserve tighter thresholds than disposable tooling.
Exploit conditions
Public proof of concept code, simple pre-auth attack paths, and low-complexity triggers should move a finding up the queue.
This is the attacker view defenders often skip. CVSS may tell you a flaw is severe. It does not tell you whether an operator can chain it with weak IAM, poor segmentation, or a secret mounted into /var/run/secrets.
Close the loop after the patch
A ticket marked fixed proves very little. The image may have been rebuilt from the same vulnerable parent. The package may still be present in another layer. The exploit path may still work because the underlying issue was privilege or exposure, not just the package version.
A closed-loop workflow should look like this:
Confirm the finding in the deployed artifact
Verify the vulnerable component exists in the image that is running.
Check exploit preconditions
Validate reachability, execution path, privileges, and any credentials or network access that make compromise useful.
Fix the source artifact
Update the Dockerfile, dependency manifest, or base image. Do not patch the live container.
Rebuild and redeploy the image
Push a new artifact through the same pipeline and admission controls.
Re-scan and retest the exploit path
Confirm the finding is gone, then try the attack again.
That final retest is what separates reporting from security work. An attacker verifies access by using it. Defenders should verify remediation the same way.
Closing the Loop with Remediation and Offensive Verification
Attackers do not care that a ticket says resolved. They care whether the old path still lands code execution, credential access, or lateral movement.
That is why remediation has to end with verification in the deployed environment, not with a package update in source control. I have seen teams bump a dependency, close the finding, and still ship the same exposure because the vulnerable binary remained in another layer, the service was still reachable, or the container kept the privileges that made the flaw useful in the first place.
Fix the image at the source
Start with the build inputs. Change the Dockerfile, dependency manifest, or base image. Rebuild the artifact. Push it back through the same pipeline and policy gates used for any other release.
Do not patch a live container and call that remediation. That only creates drift between what is running and what can be reproduced.
The remediation workflow should stay simple:
Pin exact image versions: Mutable tags create uncertainty about what was scanned versus what was deployed.
Replace stale parent images: A large share of findings come from the base layer, not the application code.
Remove tooling you do not need: Shells, package managers, and debug utilities give an operator more room once they get a foothold.
Rebuild from code every time: The fixed state must be reproducible.
The Docker hardened image guidance supports the same approach. Reduce package count, keep dependencies current, and treat image rebuilds as the unit of remediation.
Verification closes the gap scanners miss
A scanner can tell you a package version changed. It cannot prove the original attack chain is dead.
That proof comes from retesting. If the initial issue was an RCE in a web component, send the exploit traffic again against the new image. If the finding only mattered because the container ran as root with a writable filesystem, validate those controls changed too. If access to cloud credentials or service account tokens was the payoff, confirm those secrets are no longer exposed or useful.
This is the offensive check many security programs skip. It is also the part that matters most. Adversaries validate access by using it. Defenders should validate remediation the same way.
Policy should define what "fixed" means
Remediation breaks down when engineering, security, and platform teams use different definitions of closure. A useful policy gives each group a concrete standard and keeps exception handling from turning into permanent risk acceptance.
Good programs define four things:


"Patched" is an activity label. "Retested and no longer exploitable" is the security outcome.
That standard changes team behavior. It shifts scanning away from report production and toward verified risk reduction.
A Practical Roadmap for Governance and Implementation
Attackers do not care how many scanners you bought. They care about the gaps between policy, ownership, and enforcement. Governance matters because weak governance creates the exact conditions an adversary needs: stale base images, exceptions that never expire, production workloads no one can inventory, and scanner outputs nobody trusts enough to act on.


Set policy before you buy tooling
Start by deciding what would make you stop a deployment, what can ship with a time-bound exception, and who has authority to make that call. If those rules are unclear, every scanner turns into a report generator and every release fight becomes subjective.
Policy should answer a small set of operational questions:
Deployment blockers: Which findings stop release, based on exploitability, exposed attack surface, privilege level, and asset value
Exception handling: Who can approve a delay, what evidence they need, and when that exception expires
Scan coverage: Which stages in the SDLC must scan images, dependencies, IaC, and running containers
Ownership: Which team fixes base image issues, application dependency issues, misconfigurations, and runtime drift
Trend review: How often security and platform teams review repeat failures by repo, team, or base image family
That order is not paperwork. It changes outcomes. From an attacker's perspective, undefined policy is useful because it creates room for risky images to pass under schedule pressure, especially when the finding has a high CVSS score but no clear exploit path, or a lower score tied to exposed credentials, reachable services, or container escape preconditions.
Use compliance to enforce repeatable operations
Compliance frameworks are useful when they force repeatable behavior instead of checklist theater. FedRAMP is a good example. The Knox Systems explanation of FedRAMP container vulnerability scanning requirements ties container scanning to pre-deployment review, recurring production rescans, and mapped control evidence under NIST 800-53.
That model works outside regulated environments because it forces teams to prove basic facts that attackers routinely exploit when they are missing.
Keep an accurate inventory of deployed images and tags
Show that each production image passed the required scans before release
Re-scan production on a fixed schedule, not only during builds
Quarantine or block images that drift outside policy
Retain evidence that exceptions, fixes, and rescans happened
The trade-off is straightforward. Tighter policy creates more friction for engineering teams, especially in environments with legacy images or shared base layers. Loose policy creates more opportunity for adversaries. In practice, mature programs choose friction in controlled places: release gates for internet-facing workloads, stronger runtime review for privileged containers, and strict exception expiry for anything tied to identity, secrets access, or cluster administration.
Executives should treat container vulnerability scanning as an operating discipline. The workflow starts with image policy, continues through build and runtime enforcement, and ends when the original attack path is no longer usable.


