# Patching PHP in Kubernetes

> Patch a Kubernetes PHP image after PHP2Shell: find vulnerable pods, rebuild images, roll out all workloads and prove the state of each pod.

Source: https://phpsos.de/en/server/kubernetes/  
As of: 25/10/2026  
Provider: PHP SOS, PHP emergency help and server security. Immediate help via WhatsApp: https://wa.me/491736494914?text=Hello%20PHP%20SOS%2C%20we%20need%20help%20with%20our%20PHP%20server.%20Company%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**In short:** In Kubernetes, PHP lives in the container image, not in the cluster. After PHP2Shell, you must rebuild every Kubernetes PHP image with a fixed PHP version, roll out all affected workloads again and then check the state in every running pod. An updated base image in the registry alone changes nothing about running pods.

## Why the cluster does not patch itself

Kubernetes manages containers but does not take care of the software inside them. Every pod runs with the image it was started from until it is replaced. Anyone running PHP applications in a cluster is therefore responsible for the images, even if the cluster runs as a managed service at a cloud provider. The provider typically maintains the control plane and the nodes, not the customers' images.

PHP2Shell covers CVE-2026-109618 and CVE-2026-109619, each with CVSS v4.0 9.2. Among those affected are PHP-FPM, Apache with mod_php and FrankenPHP, which are the usual operating modes in PHP images. The fixed versions are PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35.

## Taking inventory: which Kubernetes PHP image runs where?

Start with a list of all images in the cluster. The following commands only read. Names of namespaces, deployments and containers are examples.

```bash
# All images of all pods, grouped
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}'

# Image digest actually running per container
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{range .status.containerStatuses[*]}{.imageID}{" "}{end}{"\n"}{end}'

# PHP version in a running pod
kubectl exec -n shop deploy/web -c php -- php -v
```

Besides deployments, also think of StatefulSets, DaemonSets, CronJobs and init containers. In larger clusters, image scanners that search the images for known CVEs help. For distribution packages inside the image, the same applies as everywhere: a backport can leave the version number unchanged, in which case the package's changelog counts.

## Rebuilding images

Update the base image first. If you use official PHP images, choose a variant with the fixed PHP version. Then rebuild your own image without taking over the old base layer from the cache.

```bash
# Example: rebuild the image, actively pull the base image again
docker build --pull --no-cache -t registry.example.com/shop/web:2026-10-25 .

# Check the PHP version in the new image before the rollout
docker run --rm registry.example.com/shop/web:2026-10-25 php -v
```

Do not rely on tags such as `latest` or a bare major version. In the manifest, reference the digest of the new image wherever possible, so it is unambiguous which state is being rolled out. If deployment runs through GitOps or Helm, change the image there so that the state is not reset at the next reconciliation.

## Rollout and verification

A new rollout replaces all pods of a workload step by step. Afterwards, you check the state in the running pods. Only then is the patch effective, because new files only help if old PHP processes are no longer running.

```bash
# Rollout with the new image (names as an example)
kubectl -n shop set image deploy/web php=registry.example.com/shop/web@sha256:<digest>
kubectl -n shop rollout status deploy/web

# Check: all pods restarted, new digest active?
kubectl -n shop get pods -o wide
kubectl -n shop exec deploy/web -c php -- php -v
```

If the image was pushed again under the same tag, `kubectl rollout restart` triggers a restart; however, pods only pull the image again if the `imagePullPolicy` provides for it. Switching to a new digest is safer.

> **Important:**
> Save logs before you replace pods. When the old pod goes, its local logs disappear with it. Keep web server and application logs from 20 October 2026 onward, ideally in a central log platform.

## Interim measures in the cluster

If no fixed image is available yet for your PHP version, php.net recommends interim measures without complete protection. In the cluster, you set memory limits through the containers' resource limits, which are based on cgroups. This corresponds to the recommendation to limit memory via container or cgroups and not via `RLIMIT_AS` or `RLIMIT_DATA`.

```ini
; php.ini or FPM pool in the image, e.g. mounted via ConfigMap
session.upload_progress.enabled = 0
post_max_size = 8M
upload_max_filesize = 6M
```

With an upload function, php.net gives `post_max_size = 32M`. On PHP 8.5, `fatal_error_backtraces=0` is added. After changing the configuration, a new rollout is needed. In addition, NetworkPolicies limit outgoing connections of the PHP pods, and an ingress with protection rules can make attack attempts harder. According to Cloudflare, however, rules based on the request data alone are not sufficient.

## Positioning yourself better for the long term

Plan regular automatic rebuilds of all PHP images, an image check in the build chain and policies that admit only signed or verified images. If PHP containers run with a non-root user and a read-only file system, the damage from a successful attack is smaller. Notes for individual containers are under [Patching PHP in Docker containers](https://phpsos.de/en/php2shell/docker-container-patchen/), for FrankenPHP under [Securing FrankenPHP](https://phpsos.de/en/server/frankenphp/).

In many clusters, PHP applications do not run alone. There are often sidecar containers for logging or metrics, helper images for database migrations and jobs that only start at night. Third-party images, for example for a wiki, a monitoring interface or a ticket system, can also contain PHP without this being recognizable from the name. So check not only your own applications but every image in the cluster. For third-party images, the following applies: wait for an updated version from the vendor, check its statements on the PHP version included, and limit reachability until it is available. If such a system only runs internally, that lowers the risk but does not replace the update.

## How does PHP SOS help?

- We record all workloads with PHP, their images and digests and check the PHP version in running pods.
- Through the [PHP patch service](https://phpsos.de/en/leistungen/php-patch-service/), we rebuild images, roll them out and document the state per workload.
- We preserve logs before the swap and check for traces of an attack.
- With [security monitoring](https://phpsos.de/en/leistungen/security-monitoring/) and automated rebuilds, we make sure the next patch reaches the cluster faster.


## Frequently asked questions

**Is it enough to update the base image in the registry?**  
No. Running pods keep using the image they were started with. Only a new rollout with the rebuilt image replaces the pods. Afterwards, check the PHP version in every running pod.

**Why reference images by digest?**  
A tag can point to different image states, depending on when it was pulled. A digest names exactly one state. That way you know for certain which code runs in which pod, and rollouts become traceable.

**What about CronJobs and init containers?**  
They can also contain PHP and belong in the inventory. CronJobs start new pods from their template on every run; update the image in the template. Init containers run at the start of every pod.

**Does a NetworkPolicy protect against PHP2Shell?**  
It does not close the vulnerability, but it can limit the damage. Restricting outgoing connections from PHP pods makes it harder to download malicious code and to move sideways in the cluster.

## Sources

- [php.net: Security announcements](https://www.php.net/)
- [PHP 8 ChangeLog](https://www.php.net/ChangeLog-8.php)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
- [BSI (German Federal Office for Information Security)](https://www.bsi.bund.de/)
