New to Rust? Grab our free Rust for Beginners eBook Get it free →
Methods to Seal Kubernetes Applications from Vulnerabilities

I ran a scan against my own cluster last month. Trivy reported three high-severity CVEs from 2025, all exploitable through configurations I thought were safe. The official CVE feed publishes new advisories almost every month, and the ones that matter now let an attacker pivot from a single misconfigured pod to the entire control plane.
The three vulnerability classes below each come with a configuration change that closes the hole today.
The CVEs that matter right now
| CVE | Component | Severity | Attack vector |
| CVE-2025-1974 | Ingress NGINX Controller | 9.8 CRITICAL | Ingress object write |
| CVE-2025-31133, 52565, 52881 | runC runtime | 9.8 CRIMAL | Container escape |
| CVE-2020-8554 | Kubernetes Service | 6.5 MEDIUM | Namespace traffic theft |
IngressNightmare is the name security researchers gave to a set of four CVEs in the Ingress NGINX Controller. The set includes CVE-2025-1974, CVE-2025-1097, CVE-2025-1098, and CVE-2025-24514. The highest-severity of the four is CVE-2025-1974.
It lets an attacker who can create or update an Ingress object inject arbitrary configuration into the controller and read every secret in the cluster. The exploit works without any credential beyond the ability to write to the Ingress API.
The second class is the runC escape chain. The three CVEs in this class are CVE-2025-31133, CVE-2025-52565, and CVE-2025-52881. runC is the container runtime underneath Docker and containerd.
These three CVEs let a process inside a container break out to the host and gain root.
Any cluster running an unpatched runC version is exposed, and the vulnerability has been public since early 2025.
The third class is older but still unpatched in many environments. That class is CVE-2020-8554. This one lets a tenant with the ability to create a Service in any namespace steal traffic from Services in other namespaces.
There is no code fix from the Kubernetes project. The mitigation is a webhook or admission controller that blocks the attack.
Harden the control plane and nodes
- RBAC enabled on the cluster
- kubectl configured for your cluster
- Access to the API server audit configuration
Before you scan anything, confirm the basics are in place. These are the prerequisites that make every other defense meaningful.
Enable RBAC and use it. The default Kubernetes configuration grants broad permissions to service accounts. Every namespace should have its own Role and RoleBinding, scoped to the minimum set of resources and verbs the workloads in that namespace actually need.
If you are still using the default service account for application pods, create a dedicated one and bind it to a role that only lists the resources it uses.
Disable SSH access to nodes. Direct SSH to a Kubernetes node gives an attacker access to the host, the kubelet, and every container running on that node. Use kubectl exec to get a shell inside a container instead.
If your team needs node-level debugging, route it through a bastion or a dedicated debug container with a short TTL.
Enable audit logging on the API server. Audit logs record every request to the control plane. Without them, you cannot tell whether an IngressNightmare exploit actually happened.
Configure the audit policy to log metadata for all requests and full request/response for write operations on Ingress, Service, and Secret resources.
Enforce Pod Security Admission
PodSecurityPolicy was deprecated in Kubernetes 1.21 and removed in 1.25. The replacement is Pod Security Admission, a built-in controller that enforces Pod Security Standards at the namespace level. If your cluster is still on a version that supports PSP, you are running a security model the project has already retired.
PSA has three profiles. Baseline blocks common privilege escalations like running as host users, mounting the host filesystem, and using host networking. Restricted adds limits on capability sets, seccomp profiles, and user namespaces.
Privileged allows everything and should only be used for system-level components that genuinely need it.
Apply the restricted profile to every namespace that runs application workloads. The label on the namespace decides the level:
kubectl label namespace my-app pod-security.kubernetes.io/enforce=restricted
When a pod does not meet the profile, the API server rejects it at creation time. That means a developer who tries to run a privileged container gets an immediate error instead of a runtime surprise. Run the label in audit mode first if you want to see what would break before you enforce:
kubectl label namespace my-app pod-security.kubernetes.io/audit=restricted
Scan images and configs before they ship
- Container image CVEs
- Misconfigurations against Pod Security Standards
- Secrets in source code and config files
- SBOM generation for supply-chain tracking
Trivy is a scanner that covers both container images and live cluster configuration. It is open source, maintained by Aqua Security, and it handles CVEs, misconfigurations, secrets, and SBOM generation in one tool. The command below scans a container image for known vulnerabilities:
trivy image --severity HIGH,CRITICAL my-registry/my-app:latest
For a live cluster scan, Trivy checks the running configuration against the same Pod Security Standards you would enforce with PSA:
trivy k8s --severity HIGH,CRITICAL --report summary cluster
The output groups findings by severity and namespace, so you can see at a glance which workloads are running with elevated privileges or missing security contexts. I run this command in a CI job that gates every merge to the main branch. If a new deployment introduces a HIGH or CRITICAL finding, the pipeline fails.
For the IngressNightmare CVEs specifically, Trivy also scans the Ingress NGINX Controller version itself. If your cluster runs a vulnerable controller version, the scan flags it with the CVE ID and the fixed version number.
Lock down runtime and network
Network Policies are Kubernetes-native firewall rules. Without them, every pod can reach every other pod in the cluster. That means a compromised frontend can talk directly to your database, your internal APIs, and your metadata service.
The policy below denies all ingress and egress by default, then opens only the specific paths the application needs:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: my-app
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Once the default-deny policy is in place, add a second policy that allows the specific traffic your application requires. The key is to start from zero trust and open only what is needed, rather than trying to block known-bad traffic after the fact.
For runtime monitoring, Falco or Tracee can detect the behavior that CVE exploits produce. A container suddenly opening a raw socket, a process writing to /etc on the host, a shell spawning inside a production container. These tools do not prevent the exploit, but they give you a signal fast enough to respond before the attacker pivots.
When the scan finds a CVE you cannot patch yet
| CVE | Status | Workaround |
| CVE-2020-8554 | No code fix planned | Admission webhook blocks the attack |
| CVE-2025-31133 and similar runC escapes | Runtime update required, some workloads blocked | PSA restricted profile + network policy for metadata and API egress |
Not every CVE has a fix available. CVE-2020-8554 is the clearest example. The Kubernetes Security Response Committee published the advisory, confirmed the vulnerability, and stated that the fix is a webhook or admission controller rather than a code patch.
If your scan reports it, the mitigation is to block the attack at the admission layer.
For runC escapes, the fix is a runtime update, but some workloads depend on a specific container runtime version. In that case, the short-term mitigation is to enforce the restricted PSA profile and add a Network Policy that blocks egress to the metadata service and the Kubernetes API from application pods. That does not fix the escape, but it limits what an attacker can do after they reach the host.
Build a CVE-feed habit
| Tool | Frequency | What it does |
| Kubernetes CVE feed | Check monthly | Lists new CVEs with affected and fixed versions |
| Trivy cluster scan | Weekly | Scans running cluster config against PSA and known CVEs |
| Trivy image scan | On every build | Scans container images before they ship to the registry |
The official Kubernetes CVE feed at kubernetes.io/docs/reference/issues-security/official-cve-feed/ is the source of truth. It lists every CVE that affects Kubernetes itself, with the affected versions, the fixed versions, and a severity rating. Subscribe to it as an RSS feed or check it monthly.
I run the Trivy cluster scan on a schedule, once a week, with results piped to a Slack channel. The output tells me whether any new CVEs apply to the images or configurations we are running. If you do not have a Slack channel for it, a weekly cron job that emails the report to the on-call address works just as well.
The command below is the one I would run if I could only run one. It scans the cluster, filters to high and critical findings, and prints a summary. Run it against your own cluster and see what comes back.
trivy k8s --severity HIGH,CRITICAL --report summary cluster
Frequently asked questions
Here are the questions that come up when teams start scanning their clusters against the current CVE feed.




