July 21, 2026
5 Kubernetes YAML Anti-Patterns I Still See in Production (And How to Fix Them)
Unfortunately, I still see serious security risks in production environments. Therefore, I would like to highlight five common mistakes…

By TheYAMLGuy
2 min read
Unfortunately, I still see serious security risks in production environments. Therefore, I would like to highlight five common mistakes, explain their impact, and show how to fix them.
1. Using the latest Image Tag
Classic one.
# BAD: Using the latest tag
spec:
containers:
- name: app-container
image: myregistry.azurecr.io/app:latest# BAD: Using the latest tag
spec:
containers:
- name: app-container
image: myregistry.azurecr.io/app:latestWhy it's a problem:
This flaw opens the door to supply chain attacks. An attacker with access to the image registry can publish an infected version; Kubernetes would then deploy that infected version, resulting in a security incident.
Additionally, it breaks deterministic deployments, two pods started on different days might run completely different code versions without you realizing it. How to fix it:
Always pin your container images to explicit semantic versions or immutable SHA-256 digests.
# GOOD: Using explicit versioning
spec:
containers:
- name: app-container
image: myregistry.azurecr.io/app:v1.4.2
imagePullPolicy: IfNotPresent# GOOD: Using explicit versioning
spec:
containers:
- name: app-container
image: myregistry.azurecr.io/app:v1.4.2
imagePullPolicy: IfNotPresent- Running Containers as Root
By default, Kubernetes containers run as the root user unless you explicitly tell them not to.
# BAD: No security context defined
spec:
containers:
- name: web-app
image: nginx# BAD: No security context defined
spec:
containers:
- name: web-app
image: nginxWhy it's a problem:
If an attacker exploits an application vulnerability (like a Remote Code Execution), they instantly get root privileges inside the container. This makes container escape attacks on the host node significantly easier. How to fix it:
Enforce non-root execution via the securityContext.
# GOOD: Restricting privileges
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
containers:
- name: web-app
image: nginxinc/nginx-unprivileged:alpine
securityContext:
allowPrivilegeEscalation: false# GOOD: Restricting privileges
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
containers:
- name: web-app
image: nginxinc/nginx-unprivileged:alpine
securityContext:
allowPrivilegeEscalation: false- Omitting CPU and Memory Limits
Deploying workloads without setting boundaries for compute resources.
# BAD: Unbounded resource consumption
spec:
containers:
- name: backend
image: backend-service:v1.0# BAD: Unbounded resource consumption
spec:
containers:
- name: backend
image: backend-service:v1.0Why it's a problem:
A single pod with a memory leak can consume all available memory on a worker node. This triggers the Node OOM killer, causing unexpected evictions of other critical pods running on the same node. How to fix it:
Define clear requests for scheduling and limits to set an absolute ceiling.
# GOOD: Explicit resource boundaries
spec:
containers:
- name: backend
image: backend-service:v1.0
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"# GOOD: Explicit resource boundaries
spec:
containers:
- name: backend
image: backend-service:v1.0
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"- Missing Liveness and Readiness Probes
Assuming Kubernetes knows your application state just because the process hasn't crashed.
# BAD: No health checks configured
spec:
containers:
- name: api
image: api-service:v2.0# BAD: No health checks configured
spec:
containers:
- name: api
image: api-service:v2.0Why it's a problem:
If your app takes 30 seconds to boot or gets deadlocked in a database connection loop, Kubernetes will still route live user traffic to it, resulting in HTTP 500 errors for your users. How to fix it:
Add explicit readiness and liveness endpoints.
# GOOD: Probes configured
spec:
containers:
- name: api
image: api-service:v2.0
readinessProbe:
httpGet:
path: /healthz/ready
port: 8080
livenessProbe:
httpGet:
path: /healthz/live
port: 8080# GOOD: Probes configured
spec:
containers:
- name: api
image: api-service:v2.0
readinessProbe:
httpGet:
path: /healthz/ready
port: 8080
livenessProbe:
httpGet:
path: /healthz/live
port: 8080- Hardcoding Secrets in ConfigMaps
Putting raw API keys, tokens, or passwords directly into plain-text manifests.
# BAD: Plain-text credentials
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DB_PASSWORD: "NothingToSeeHere"# BAD: Plain-text credentials
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DB_PASSWORD: "NothingToSeeHere"Why it's a problem:
ConfigMaps are stored unencrypted in etcd by default and can be read by anyone with basic namespace read access. They also frequently leak into system logs. How to fix it:
Use native Kubernetes Secrets (encrypted at rest) or inject them via a Secret Manager (e.g., HashiCorp Vault, AWS Secrets Manager).
# GOOD: Referencing a secret object
spec:
containers:
- name: app
image: app:v1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password# GOOD: Referencing a secret object
spec:
containers:
- name: app
image: app:v1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: passwordFixing these five points, makes your cluster a bit safer.