A Kubernetes manifest is safe to apply when the pod cannot gain more power on the node than it needs, when the image you run is the image you reviewed, when memory and CPU have a ceiling, and when the cluster can tell whether the container is alive and ready for traffic. Six groups of fields decide most of that: the securityContext, host access, image references, resource requests and limits, probes, and where secrets come from. None of them is exotic. They are the defaults you leave in place when a manifest is copied from a tutorial, and each one has a small, boring replacement.
Why a handful of fields matter more than the others
A manifest has hundreds of fields, but a review does not have to read all of them with the same care. Most fields describe what to run. A few describe how much the workload may take from the node it lands on, and those are the ones where a mistake is felt by other teams: a neighbour that gets evicted, a node that runs out of memory, a container that escapes into the host. The Kubernetes project already ranks these fields for you in its Pod Security Standards, which define three profiles. The widest one, Privileged, is defined by the absence of restrictions. Baseline blocks the known escalation routes. Restricted adds current hardening practice on top (Pod Security Standards). Reading a manifest against Baseline first, then Restricted, gives you an ordered checklist rather than a vague feeling of unease.
1. Privileged mode and who the process runs as
The first field to look for is privileged: true inside a container's securityContext. The standards state that a privileged pod disables most of the isolation mechanisms, so Baseline forbids it (Pod Security Standards). If a manifest sets it, the question to ask is which single capability the process really needs. A network tool may need one capability added; it almost never needs the whole kernel surface.
Next comes the user. Restricted requires runAsNonRoot: true, and the per-container fields may stay empty if the setting is already true for the whole pod. It also refuses a runAsUser of 0. A related field is allowPrivilegeEscalation, which Restricted requires to be false, so a process cannot gain rights through a set-user-ID binary. The same profile asks for an explicit seccomp profile, with RuntimeDefault as the usual value (Pod Security Standards).
The practical consequence is that an image built to run as root will start failing once you set runAsNonRoot. That is the point of the setting, but it means the change belongs in the same pull request as a fix to the image, not as a surprise in production. A short block that satisfies most of the above looks like this:
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
seccompProfile:
type: RuntimeDefault
2. Access to the host
Three fields connect a pod to the machine under it: hostNetwork, hostPID and hostIPC. Baseline requires all three to be unset or false, because sharing those namespaces lets a container see traffic or processes that belong to the node and to other pods. A fourth, hostPort, ties a container to a port on the node itself and is better replaced by a Service.
The one that appears most often in copied manifests is a hostPath volume. It mounts a directory of the node into the container. Baseline bans these volumes outright, and the volume types that Restricted still allows include configMap, secret, emptyDir, persistentVolumeClaim, projected, downwardAPI, csi and ephemeral (Pod Security Standards). If a workload needs scratch space, emptyDir gives it a directory that disappears with the pod. If it needs durable data, a persistent volume claim does the job without tying the pod to one node's disk. A real need for node paths exists, for log collectors and some drivers, but it belongs to a separate namespace with its own policy rather than to an ordinary application.
3. Image references
An image written as a name with no tag is not neutral. The images documentation says Kubernetes assumes the tag latest when none is given, and that a tag may later be re-pointed at a different image, while a digest never changes since it is computed from what the image contains (Images). Two consequences follow. The version running today may not be the version running after the next node restart, since a pod rescheduled elsewhere can pull a newer image. And a rollback is unreliable when the "old" version has the same name as the new one.
Pin to a specific version tag at minimum, and to a digest where the registry is outside your control. The digest form looks like image: registry.example/app@sha256:<hash>, and tooling can update it automatically so the pin does not turn into a maintenance burden.
4. Requests and limits
Resource limits and requests do different work. The scheduler uses the request to choose a node, and the kubelet reserves at least that amount for the container. The limit is the cap that the node enforces. The documentation describes the two limits differently: a CPU limit throttles the container when it approaches the ceiling, whereas a memory limit is enforced by the kernel through out-of-memory kills, and only when the kernel sees memory pressure (Resource management).
A container with no memory limit can grow until the node itself is short of memory, and then something is killed that you did not choose. A container with a limit that is too low is killed repeatedly and shows up as restarts with an out-of-memory reason. Both are manifest problems, which is why a review looks for a memory limit on every container and compares it with what the application actually uses. A request that is far below real use is the quieter sibling: the pod schedules easily, then competes with its neighbours.
Setting the request equal to the limit for memory is a common, defensible pattern for services that must not be surprised. CPU limits are more debated, because throttling can add latency even when the node has idle cores; many teams set a CPU request and leave the limit out. Either way, the choice should be written down on purpose and not inherited by accident.
5. Probes
Probes are how the cluster learns about the health of a container, and a manifest without them is a manifest that tells Kubernetes nothing. The probes page describes three kinds. A liveness probe decides whether the container should be restarted. A readiness probe decides whether the pod receives traffic from a Service, and it keeps running for the whole life of the container. A startup probe protects slow-starting applications, so that the liveness probe does not kill them during initialisation (Probes).
The most damaging mistake is a liveness probe that depends on something outside the pod, for example a database call. When the database is slow, every replica fails liveness together and the cluster restarts the whole service at the moment it can least afford it. A liveness check should only ask whether the process itself is stuck. The readiness probe is the place for dependencies, since removing a pod from the Service rotation is a milder reaction than a restart. The page also warns that readiness and liveness do not wait for each other, so each must be correct alone.
6. Secrets in the manifest
A password written as a literal value: under env is stored wherever the manifest is stored: in Git history, in CI logs, in kubectl get -o yaml output. Reading it from a Secret with secretKeyRef, or mounting the Secret as a volume, keeps the value out of the file you review. That does not make the secret safe by itself, since a Secret object is only encoded unless you add encryption at rest and tight access rules, but it moves the problem to the place where it can be solved.
A review order that works
Read the manifest in this order, and stop to ask a question at each step. Is anything privileged or sharing the host? Who is the user? Is every image pinned? Does every container have a memory limit? Are both probes present, and does liveness avoid outside dependencies? Does a literal credential appear anywhere? Third-party manifests deserve the same reading as any other file you did not write, for the reason given in our note on why unvetted agent files are a risk, agent skills security risks: you are about to run what the file says, with the permissions the file asks for.
When this does not apply
What follows are the limits of this checklist, which is a first pass over a single Pod or Deployment.
- It does not replace cluster policy. A good manifest can still be applied into a namespace with no admission control, and a bad one can be blocked by a policy engine before it runs. Network rules and access control for the API are separate subjects.
- It follows the current Kubernetes documentation, read on 27 October 2026. Field names and profile contents change between versions, and your cluster may be older than the pages cited here.
- System components, storage drivers and node agents sometimes need exactly the settings listed above as risky. In those cases the right outcome is a documented exception in a dedicated namespace, not a rewrite.
- Memory and CPU values cannot be judged from the manifest alone. A limit is right or wrong only against measured use, and we did not measure any workload for this guide.
- Probes that look correct on paper can still fail in practice, because timing values depend on how long your application really takes to start.
A second reader for your own manifest
Before a manifest is applied, the skill kubernetes-manifest-review reads one Pod or Deployment and answers with only the unsafe settings it finds, each with the container involved, the reason it hurts and the fix, or a plain statement that nothing was found. It is aimed at the privileged and root cases, unpinned images, missing memory limits, literal secrets and host path volumes, and it leaves alone the safe lookalikes such as an image pinned by digest or a read-only config volume. The full store is at https://aiskills402.com.
Read this post as Markdown: /blog/kubernetes-manifest-risks.md · Atom feed.
