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

CVEComponentSeverityAttack vector
CVE-2025-1974Ingress NGINX Controller9.8 CRITICALIngress object write
CVE-2025-31133, 52565, 52881runC runtime9.8 CRIMALContainer escape
CVE-2020-8554Kubernetes Service6.5 MEDIUMNamespace 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

CVEStatusWorkaround
CVE-2020-8554No code fix plannedAdmission webhook blocks the attack
CVE-2025-31133 and similar runC escapesRuntime update required, some workloads blockedPSA 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

ToolFrequencyWhat it does
Kubernetes CVE feedCheck monthlyLists new CVEs with affected and fixed versions
Trivy cluster scanWeeklyScans running cluster config against PSA and known CVEs
Trivy image scanOn every buildScans 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.

What is the highest-severity Kubernetes CVE in 2025?

CVE-2025-1974, part of the IngressNightmare set, is the highest-severity. It lets an attacker who can write to the Ingress API read every secret in the cluster. The fix is to update the Ingress NGINX Controller to the patched version and restrict who can create or update Ingress objects.

Do I need Pod Security Admission if I already use a pod security tool?

PSA is built into the API server and runs before any third-party tool sees the request. It is the first line of defense, not a replacement for runtime scanning. Use PSA to block common misconfigurations at admission time, and use a runtime tool like Falco to catch behavior that slips through.

How often should I scan your cluster for CVEs?

At least monthly, ideally weekly. The official Kubernetes CVE feed publishes new advisories almost every month, and container images are rebuilt frequently. A weekly scan catches new CVEs before they sit in your cluster for months.
Pankaj Kumar
Pankaj Kumar

Pankaj Kumar is the founder and CEO of CodeForGeek, with more than 14 years in IT. He is an open-source enthusiast who enjoys sharing what he learns through CodeForGeek and YouTube, with a focus on Python, data analytics, machine learning, Angular, Node.js, and Kafka.

Articles: 335