Patch Released Is Not Patch Installed: The Hidden Delay Between a PHP Fix and Your Server
Upstream ships source at a fixed hour; your packages follow on their own schedule — sometimes hours later. How to see where the fix actually is, and what to do in the gap.
On 21 October 2026 the PHP security team released 8.2.35, 8.3.36, 8.4.27 and 8.5.12 to fix two critical remote code execution flaws (CVE-2026-109618 and CVE-2026-109619). The announcement gave an exact time. Many administrators read it as "we patch at that time". In practice, the moment PHP publishes source code is only the first link in a chain, and every later link has its own delay.
We patched a set of servers that day and watched each link fail in turn. This is what we learned.
The chain between "released" and "running"
- Upstream source. php.net publishes tarballs and the GitHub security advisories. Nothing on your server changes.
- Package builds. Your distribution or a third-party repository (for Ubuntu, very often
ppa:ondrej/php) rebuilds each branch for each OS release and each CPU architecture. A build can be "done" for amd64 while arm64 is still compiling. - Publication. A finished build is not yet downloadable. The repository has to publish the binaries into its index. On Launchpad, a source package can show as Published while its binary packages are still pending.
- Mirrors and download servers. On a release day everyone downloads at once. We saw the download server for a widely used PPA answer HTTP 503 for hours, and
apt-get updatesilently kept the old index. - Your
apt. Only after a successful index refresh doesaptsee a new candidate version. - Your running processes. Installing the package replaces files on disk; already running workers keep the old code until they restart (see our separate guide on restarting).
Container images add a link of their own. Official images rebuild on their own schedule, and an image built FROM an old, pinned base tag never receives the fix until you rebuild it on a current one.
How to see where the fix really is
Check the candidate apt will install, after refreshing the index:
sudo apt-get update
apt-cache policy php8.4-fpm
If Candidate still shows the old version, look upstream of your mirror. For a Launchpad PPA, the public API shows both the source and the binary state:
curl -s "https://api.launchpad.net/1.0/~ondrej/+archive/ubuntu/php?ws.op=getPublishedSources&source_name=php8.4&distro_series=https://api.launchpad.net/1.0/ubuntu/jammy&exact_match=true&ws.size=1" \
| python3 -c "import json,sys; e=json.load(sys.stdin)['entries'][0]; print(e['source_package_version'], e['status'])"
Pending means it is not published yet. Published with an empty binaryFileUrls list means the binaries for your architecture are not out yet either.
Finally, check what is actually running, not what is installed:
php-fpm8.4 -v
dpkg-query -W -f='${Version}\n' php8.4-fpm
What to do while you wait
- Apply the vendor's interim mitigations immediately. For CVE-2026-109619, PHP's advisory names
session.upload_progress.enabled = 0for the confirmed session path, and on PHP 8.5fatal_error_backtraces = 0. Both advisories also say plainly that updating is the only complete mitigation, so treat these as a bridge, not a destination. - Shrink who can reach PHP. If your sites sit behind a CDN or WAF, make sure the origin cannot be reached directly (we wrote a separate guide on locking your origin).
- Don't install unpublished build output. A build that a repository has not yet published has not been through its normal release path. Waiting an hour is usually the right trade.
- If only the download server is the problem, there is a middle path. Once binaries are published, Launchpad also lists them on the PPA's file pages, and you can fetch the exact
.debfiles and install them withapt install ./*.deb. Be honest about the trade-off: these files are fetched over HTTPS from the repository host, but you skip apt's signed-index verification, so pin exact versions and check them before installing.
Measure the delay, plan for it
Write down, for each server, which repository each runtime comes from and how long the last security release took to arrive. Ours ranged from under an hour to most of an evening for the same PHP release, depending on the branch and the OS release. A runbook that says "patch at 14:00 UTC" should say "mitigate at 14:00 UTC, patch when the package is visible to apt, verify the running version".
Sources
- GHSA-w8hw-w9fx-j79w — RCE via OOM corruption (CVE-2026-109618) — php-src
- GHSA-6wmf-4rv5-p3rp — RCE via stale global state (CVE-2026-109619) — php-src
- PHP: News Archive 2026 — php.net
- Launchpad web services API — Launchpad