Yes. PHP is still a reasonable and safe choice in 2026, provided you run a release line that still gets security fixes, can roll out a runtime patch within days rather than months, and manage your Composer packages and plugins as carefully as your own code. The language did not become unsafe this week. Estates that cannot patch quickly were always exposed, and this week made that visible.
The question is everywhere because of how loud the past few days were. On 21 October 2026 the PHP project shipped emergency releases for two critical flaws in the interpreter itself, each rated 9.2 under CVSS v4.0, which can allow remote code execution without logging in. The NSA, FBI and CISA urged organisations to update immediately, and the FBI advised taking systems offline if an update was not feasible, according to Defense One. Government sites in several countries went dark for a day. Headlines repeated that PHP runs about 70 percent of the web, which is roughly what W3Techs measures: 69.3 percent of websites whose server side language it can identify.
If you want the incident itself, read our explainer on the two critical PHP flaws and the hands-on guide to finding and patching every PHP runtime. This post answers the broader question that CTOs, agency owners and developers are now typing into search boxes: is PHP itself the problem, and what does a PHP estate in good shape actually look like?
Key takeaways
- One critical interpreter bug does not make a language unsafe. Every major runtime written in C or C++ ships critical fixes. What matters is how fast the project fixes, how fast you deploy, and how much of your estate is on lines that no longer get fixes.
- Only four PHP lines get fixes today: 8.2, 8.3, 8.4 and 8.5. Each line gets two years of active support and two more of security fixes. PHP 8.2 reaches end of life on 31 December 2026, ten weeks from now.
- Most real PHP risk is not in the interpreter. It sits in application code, plugins, themes and Composer packages. In WordPress, one annual report counted 11,334 new vulnerabilities in 2025, with 91 percent in plugins and six in core.
- composer.json does not tell you what PHP runs in production. Check the actual binaries in each host, container image and hosting panel, and remember that distributions backport fixes without changing the upstream version number.
- Lock files help you patch fast, if you use them properly. Targeted
composer updateof one package, a commit of the new lock file and a rebuild is a same day change. Unlocked or hand editedvendorfolders are not. - Hardening still matters, but it is a second line.
disable_functionsandopen_basedirare documented by PHP itself as bypassable safety nets. Process isolation, unprivileged users and read only containers do more. - Moving off PHP is an engineering decision, not a security fix. Rewrites carry their own risk and take years. Getting current and staying current takes weeks.
Does one critical runtime bug make PHP "unsafe"?
No, and it helps to be precise about why.
PHP, like Python, Ruby and Node.js, is a memory managed language running on an interpreter written in C or C++. Your PHP application code cannot overflow a buffer the way C code can. The interpreter underneath it can still have memory safety bugs, and when one of those is reachable from an HTTP request before any of your code runs, it is serious. That is exactly what happened in October. According to the PHP project's own advisory, one flaw lets out of memory handling interrupt PHP while request data is only partly initialised, and the other lets request owned state outlive its freed memory so a later request on the same worker can use it. The project said risk was highest for Apache with mod_php, where a demonstrated exploit could fire before application code ran.
That class of bug is not unique to PHP. Every interpreter and runtime with a large C or C++ core has shipped critical fixes in the last five years, and every one of them maintains a formal security support phase precisely because more fixes will come. The useful questions are about process, not reputation:
- Does the project fix quickly and publish clearly? On this occasion, PHP gave a day of advance notice, released fixes for four supported lines at a scheduled time, published minimal source backports for three end of life lines, and said plainly that updating was the only complete fix. That is a mature response.
- Does the project own its mistakes? The PHP Foundation said early signs of one of the flaws were found by a researcher in 2024 and called the delay "a structural failure", as reported by The Standard. That is uncomfortable, and it is also the kind of candour you want from a project you depend on.
- Is the exposure concentrated or spread out? PHP's install base is enormous and long tailed, which is the real issue. W3Techs reports that among PHP sites it can classify, 26.9 percent still run PHP 7 and 7.7 percent run PHP 5. Every one of those lines stopped getting fixes years ago.
What PHP's track record looks like
Looking back over roughly five years, the interpreter has had a handful of serious, widely reported issues rather than a steady stream:
| When | What | Lesson |
|---|---|---|
| March 2021 | Malicious commits were pushed to the php-src repository on the project's own git server and reverted quickly; the project moved its canonical repository to GitHub | Language supply chains can be targeted too; the project changed infrastructure |
| June 2024 | An argument injection flaw in PHP running as CGI on Windows, a bypass of a 2012 bug, was exploited within days and added to CISA's known exploited list (see our explainer) | Old deployment modes (php-cgi, XAMPP defaults) carry old risk |
| October 2026 | Two critical memory safety flaws reachable before application code, fixed in 8.2 to 8.5 | Patch speed across the estate is the deciding factor |
The far bigger historical drag on PHP's reputation came from language features that encouraged insecure code in the PHP 4 and early PHP 5 era: register_globals, magic quotes and the old mysql_ functions. All three were removed long ago (the first two in PHP 5.4, the last in PHP 7.0). Modern PHP with strict types, prepared statements and a framework's escaping by default is a very different language from the one that earned the jokes.
So the honest answer to "is PHP unsafe because of this?" is that a current, patched PHP 8.3, 8.4 or 8.5 is about as safe as any other mainstream web runtime. An unpatched PHP 7.4 on a forgotten server is not, and it was not safe last month either.
Which PHP versions get security fixes, and for how long?
The PHP project publishes its policy on the supported versions page. Each release line gets two years of active support, with bug and security fixes and regular point releases, followed by two years of security only support, where only critical security issues are fixed and releases happen as needed. Four years in total, then end of life.
As of 23 October 2026:
| PHP line | First released | Active support until | Security fixes until | Status today |
|---|---|---|---|---|
| 8.5 | 20 Nov 2025 | 31 Dec 2027 | 31 Dec 2029 | Active |
| 8.4 | 21 Nov 2024 | 31 Dec 2026 | 31 Dec 2028 | Active |
| 8.3 | 23 Nov 2023 | 31 Dec 2025 | 31 Dec 2027 | Security fixes only |
| 8.2 | 8 Dec 2022 | 31 Dec 2024 | 31 Dec 2026 | Security fixes only, ends in ten weeks |
| 8.1 | 2021 | Ended | 31 Dec 2025 | End of life (last release 8.1.34) |
| 8.0 | 2020 | Ended | 26 Nov 2023 | End of life (last release 8.0.30) |
| 7.4 | 2019 | Ended | 28 Nov 2022 | End of life (last release 7.4.33) |
| 5.6 | 2014 | Ended | 31 Dec 2018 | End of life (last release 5.6.40) |
End of life dates and final versions come from the project's end of life table. The October fixes landed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.6 is in release candidates; the project announced RC4 on 21 October with RC5 planned for 5 November 2026.
Two details catch teams out:
- "Security fixes only" means only critical ones. A line in security support will not get fixes for medium severity issues or ordinary bugs. If you are on 8.2 or 8.3, you are already on reduced coverage.
- The October backports for 7.4, 8.0 and 8.1 were an exception. The project published minimal source patches for those lines because the flaws were so severe. They are source code you would build yourself. Do not plan around this happening again.
How does that compare with other runtimes?
| Runtime | Total support per line | How it is split | Source |
|---|---|---|---|
| PHP | 4 years | 2 years active, 2 years security only | php.net |
| Python | 5 years | 2 years bugfix (3.13 and later), then security only | Python devguide |
| Node.js LTS lines | About 30 months of critical fixes | Active LTS then Maintenance LTS; odd lines unsupported after six months | Node.js releases |
PHP's window is ordinary. What is unusual is the size of the long tail running out of support.
What about distributions and long term support vendors?
Operating system distributions often ship PHP versions that upstream has already retired and backport security fixes into them for the life of the distribution release. That is legitimate, and it means a version string such as 8.1.2 on an older Ubuntu release can be patched against a flaw that upstream only fixed in 8.2 and later. It also means:
- you depend on that distribution's security team and its schedule, not PHP's;
- third party repositories and panel builds may lag; and
- the OWASP PHP configuration cheat sheet makes a point worth repeating: a distribution's extended support does not make the upstream branch supported.
If you rely on backports, record whose, for which hosts, and how you verify each fix landed.
Where does real PHP risk come from?
When a breach involves a PHP site, the interpreter is rarely the entry point. Here is how the layers usually compare.
| Layer | Who fixes it | Typical issues | How often it bites |
|---|---|---|---|
| Interpreter (php-src) | PHP project, then your distro or image | Memory safety in request parsing, SAPIs, core functions | Rare but severe; whole estate affected at once |
| Bundled and PECL extensions | PHP project, extension maintainers, distro | Parsers for images, XML, archives; native code in C | Occasional |
| Composer packages | Package maintainers | Deserialisation, injection in libraries, auth bypass in components | Regular |
| CMS plugins and themes | Plugin and theme authors, often small teams | Missing authorisation checks, SQL injection, file upload flaws, cross site scripting | Very frequent |
| Your application code | You | SQL injection, file inclusion, insecure unserialize(), type juggling in comparisons, broken access control | Very frequent |
| Deployment and configuration | You or your host | Exposed FastCGI ports, display_errors on, writable code directories, debug tools left online | Frequent |
The WordPress numbers make the point. A WordPress security firm's annual report counted 11,334 new vulnerabilities in the WordPress ecosystem in 2025, up 42 percent on 2024. Of those, 91 percent were in plugins, 9 percent in themes and just six in WordPress core, all low priority. The same report says 46 percent had no developer fix available when they were disclosed, and that the weighted median time to mass exploitation for heavily exploited flaws was five hours.
With a five hour median to mass exploitation and nearly half of flaws unpatched at disclosure, the choice of language is not the controlling variable. Inventory, update speed and the number of unmaintained plugins you run are.
Laravel, Symfony and Magento projects are no different: a lock file can hold hundreds of packages, any of which can have an advisory next week. composer audit will tell you about published advisories in what you have installed. It will not tell you about the PHP binary, the extensions compiled into it, or the plugin someone uploaded through an admin panel. We cover the Composer side in more depth in our post on auditing PHP dependencies with Composer.
PHP specific bug classes worth knowing
A few issues show up more in PHP code than elsewhere: unserialize() on untrusted data (use JSON across trust boundaries, or pass allowed_classes), include paths built from user input (keep allow_url_include off), token or hash comparisons with == instead of hash_equals(), and uploads stored where the server will execute them as PHP.
How do you find which PHP version is actually running?
This is the sub-question that trips up most teams, because the number in composer.json is not the number running in production.
Why composer.json is the wrong place to look
The "php": "^8.2" line under require in composer.json is a constraint. It tells Composer which PHP versions your dependencies must support. It does not install or select PHP. Worse, many projects set config.platform.php to pretend the platform is a specific version during dependency resolution, so the lock file can be built for a PHP version that runs nowhere. The Composer CLI documentation notes that composer check-platform-reqs ignores config.platform and checks the real platform, which makes it a useful command to run on each production host.
Step by step: build a real runtime inventory
Work through each place PHP can live. Run these as a read only sweep first; change nothing until you have the full list.
1. Linux hosts and virtual machines. Check every binary, not just the one on your PATH. Many servers have the CLI on one version and PHP-FPM or Apache's module on another.
# The CLI on PATH
php -v
# Every PHP-FPM binary and running master process
ls /usr/sbin/php-fpm* 2>/dev/null
ps -eo pid,user,args | grep -E 'php-fpm: master|php-fpm[0-9.]*' | grep -v grep
# Debian and Ubuntu: installed PHP packages and their versions
dpkg -l | grep -E '^ii\s+php[0-9.]+-(fpm|cli|common)' | awk '{print $2, $3}'
ls /etc/php/
# RHEL, Rocky, Alma, Fedora
rpm -qa | grep -E '^php' | sort
# Apache with mod_php: which module is loaded
apachectl -M 2>/dev/null | grep -i php
2. Confirm distribution backports. If the version string is below the fixed upstream version, look for the fix in the package changelog rather than assuming you are exposed or safe.
# Debian and Ubuntu
apt changelog php8.2-fpm 2>/dev/null | head -40
# RHEL family
rpm -q --changelog php-fpm | head -40
3. What the web server actually serves. A small, access controlled check page beats guessing. Put it behind authentication or an IP allowlist, read it, then delete it.
<?php
// version-check.php: remove after use
header('Content-Type: text/plain');
echo PHP_VERSION, "\n", PHP_SAPI, "\n", php_ini_loaded_file(), "\n";
Do not rely on the X-Powered-By header. With expose_php off, which is the recommended setting, it is absent, and a reverse proxy may strip or rewrite it.
4. Container images. The official php images set a PHP_VERSION environment variable, but it is still worth running the binary. Check running containers and the images in your registry, because a rebuilt image does nothing until it is redeployed.
# Running containers on a Docker host
for c in $(docker ps -q); do
echo "$(docker inspect -f '{{.Name}} {{.Config.Image}}' "$c") $(docker exec "$c" php -r 'echo PHP_VERSION;' 2>/dev/null)"
done
# A specific image, without starting the app
docker run --rm --entrypoint php your-registry/your-app:prod -v
# Kubernetes: list images in use across namespaces
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}' | sort -u
5. Hosting panels. Control panels often install several PHP versions side by side and let each site choose one. The site's selection is what matters.
# cPanel EasyApache builds
ls /opt/cpanel/ | grep ea-php
/opt/cpanel/ea-php83/root/usr/bin/php -v
# Plesk builds
ls /opt/plesk/php/
/opt/plesk/php/8.3/bin/php -v
Then check which version each site or domain is set to in the panel itself. Our post on shared hosting, cPanel and Plesk after the PHP flaws walks through this per panel.
6. Managed platforms and vendors. For PaaS offerings, managed WordPress hosts and appliances that embed PHP, you cannot run the commands yourself. Ask the provider for the PHP version and patch date in writing, and record the answer.
7. Write it down. One row per runtime: location, owner, PHP version, SAPI (FPM, mod_php, CGI, CLI), patched or not, date checked. That table is the thing you will wish you had during the next emergency.
What does a sane PHP patch cadence look like for a small team?
A small team cannot run a change board for every point release, and does not need to. A cadence that works for a team of two to ten engineers looks like this:
| Event | Target | What happens |
|---|---|---|
| PHP point release with critical security fixes | Within 72 hours, same day if the flaw is pre-authentication and remote | Rebuild images or update packages, restart all workers, verify |
| Regular PHP point release | Within two to four weeks | Bundled into the normal release train |
| Composer advisory, high or critical, in a reachable package | Within a week | Targeted composer update, tests, deploy |
| Composer advisory, low or medium | Next scheduled dependency update | Monthly batch |
| CMS plugin security update | Within 24 to 72 hours for exploited or unauthenticated flaws | Update or disable the plugin |
| PHP minor version upgrade (8.3 to 8.4) | Once a year, never later than six months before end of life | Planned project with test coverage |
Three practices make this realistic:
- Rebuild, do not patch in place. If your PHP runs in containers, a security release means changing the base image tag, rebuilding and redeploying. Keep the base image pinned to a specific patch version, such as
php:8.4.27-fpm-bookworm, and let an automated pull request bump it. Floating tags make it hard to know what you shipped. - Restart everything that loaded the old binary. PHP-FPM masters, Apache with mod_php and long running workers (queue workers, Octane, RoadRunner, FrankenPHP) keep the old code in memory until restarted. The PHP advisory's own partial mitigations repeatedly said to restart all workers.
- Keep one test that proves the site boots on the new version. A smoke test that loads the home page, logs in and runs one database query catches most upgrade problems and gives you the confidence to ship a runtime patch the same day.
How do Composer constraints and lock files help or hurt when an urgent fix lands?
They mostly help, as long as you understand which one does what.
Constraints in composer.json define the range you allow. According to the Composer versions documentation, a caret constraint like ^1.2.3 means at least 1.2.3 and below 2.0.0, and a tilde constraint like ~1.2.3 means at least 1.2.3 and below 1.3.0. Pinning to an exact version makes the solver fail if anything else needs a different one.
The lock file records exactly what is installed. When composer.lock exists, composer install installs exactly those versions, so every environment matches. That reproducibility is what lets you change one package with confidence.
When a fix lands in a Composer package:
# 1. See which installed packages have published advisories
composer audit --locked --format=table
# 2. Update only the affected package, and its own dependencies if needed
composer update vendor/package --with-dependencies
# 3. Confirm what changed
git diff composer.lock
# 4. Re-audit and run tests
composer audit --locked
vendor/bin/phpunit
# 5. In CI and production, install exactly from the lock file
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
Where it hurts:
- Constraints that are too tight. If you pinned
vendor/packageto1.4.2exactly and the fix is in 1.4.3, you have to editcomposer.jsonbefore you can update. Use caret or tilde ranges for most packages and let the lock file provide the pinning. - Constraints that block the fixed line. If the fix exists only in 3.x and you are constrained to
^2.0, you face a major upgrade under time pressure. Staying within a maintained major version of each key dependency avoids this. composer updatewith no arguments during an incident. Updating everything at once turns a one line security change into a large, risky diff. Target the package.--with-all-dependencieswhen you only needed--with-dependencies. The-Wform also moves your root requirements; use it when the solver says you must, not by default.- Committed
vendorfolders edited by hand. Some older projects commitvendorand patch files directly. Composer then cannot tell you what is really installed, and a later install overwrites the hand patch.
Composer now also supports policy based blocking of packages with published advisories during resolution, controlled by the policy.advisories.block setting, and a cooldown period for newly published versions, according to the CLI documentation. Both are useful, and both have a --no-blocking escape hatch you should document for emergencies.
One thing a lock file can never do: patch PHP itself. The runtime is not a Composer package. composer update will not move you from 8.3.35 to 8.3.36. That happens in your base image, your distribution packages or your hosting panel.
Is moving off PHP a security decision or an engineering decision?
It is an engineering decision. Treat any proposal to rewrite "for security" with care.
Arguments that sound like security but are not:
- "PHP had a critical bug." So have the runtimes you would move to. A rewrite swaps one interpreter's bug history for another's and one package ecosystem's advisories for another's.
- "PHP code is insecure." Insecure code is a property of the code and the team. A rewrite by the same team under deadline pressure will produce new bugs, and the first version of a rewrite typically has less test coverage than the system it replaces.
Legitimate reasons to move are about engineering: your team's skills and hiring pool are elsewhere, the framework has been outgrown, or a company wide platform choice would retire infrastructure you keep only for PHP. Plan such a move over years, and keep the PHP estate current in the meantime. The security fix is almost always "get to a supported line and stay there", which takes weeks.
| Option | Time to reduce risk | Risk introduced | When it makes sense |
|---|---|---|---|
| Patch within the current line | Hours to days | Very low | Always, first |
| Upgrade to a supported minor line (for example 7.4 to 8.3) | Weeks | Moderate, mostly compatibility | Any estate on an end of life line |
| Replace the CMS or framework within PHP | Months | Moderate to high | Abandoned framework or plugin set |
| Rewrite in another language | Years | High during migration | Strong engineering or business case beyond security |
| Pay for extended support from a distribution or vendor | Days to arrange | Dependency on that vendor | Bridge while an upgrade project runs |
If you look after client sites and are the one who has to explain this to an owner who does not want to pay for an upgrade, our post on what to tell a client whose site runs old PHP has wording you can borrow.
What hardening still matters?
Hardening does not replace patching. It reduces what an attacker can do after something goes wrong, and it buys time. Some controls are much stronger than others, and PHP's own documentation is candid about the weak ones.
php.ini settings
Start from the production configuration. The official Docker image ships both php.ini-development and php.ini-production, and the image documentation strongly recommends the production file for production. Then tighten:
; Hide version, keep errors in logs not pages
expose_php = Off
display_errors = Off
display_startup_errors = Off
log_errors = On
; No remote code inclusion; restrict remote reads if the app does not need them
allow_url_include = Off
allow_url_fopen = Off
; Sessions
session.use_strict_mode = 1
session.use_only_cookies = 1
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
; Limit what scripts can call and touch (safety nets, not boundaries)
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
open_basedir = /var/www/app:/tmp/app
These values follow the OWASP PHP configuration cheat sheet, which also suggests stricter session lifetimes and a longer disable_functions list. Test before you copy the full list: functions such as chmod, mkdir or move_uploaded_file may be needed by your application or CMS.
Be clear about what disable_functions and open_basedir really do. The PHP manual says disable_functions "can be circumvented" and is not a sufficient measure for shared hosting. It describes open_basedir as an extra safety net that cannot be relied on when security is needed, and notes that it does not restrict Unix domain sockets. Use them, but do not count them as isolation.
PHP-FPM pool isolation
FPM pools are where real separation starts, provided each pool runs as its own user. From the PHP-FPM configuration reference:
[shop]
user = shop-app
group = shop-app
listen = /run/php/php-fpm-shop.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Only .php files execute; .phar and anything else do not
security.limit_extensions = .php
; Settings the app cannot override with ini_set()
php_admin_value[open_basedir] = /var/www/shop:/tmp/shop
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen
php_admin_flag[allow_url_fopen] = off
; Clean environment; pass only what the pool needs
clear_env = yes
; Recycle workers periodically
pm.max_requests = 500
Key points from the reference:
- Never expose FastCGI to the network. The manual warns that an exposed FastCGI endpoint allows arbitrary code execution. Use a Unix socket when the web server is on the same host, and if you must use TCP, set
listen.allowed_clients, which otherwise accepts any address. - Use
php_admin_value, notphp_value, for security settings. Admin values cannot be overridden withini_set(). - Pools are not a full security boundary. The manual notes that all pools share one OPcache instance. Sites that must be truly separated belong in separate FPM masters, separate containers or separate machines.
Containers and the file system
The strongest practical controls for PHP are at the operating system and container level:
- Run as a non root user and make the application code read only to that user. A PHP process that cannot write to its own code directory cannot drop a web shell there.
- Use a read only root file system with writable mounts only for uploads, cache and sessions, and serve uploads from a location PHP will not execute.
- Keep build tools out of the runtime image with a multi stage build, drop Linux capabilities, and restrict outbound network access to what the app needs.
A minimal multi stage Dockerfile that applies most of this:
# Build stage: Composer and dependencies
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-interaction --prefer-dist --no-scripts --optimize-autoloader
# Runtime stage: pinned PHP patch version
FROM php:8.4.27-fpm-bookworm
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY docker/php/security.ini "$PHP_INI_DIR/conf.d/zz-security.ini"
WORKDIR /var/www/app
COPY --from=vendor /app/vendor ./vendor
COPY . .
RUN chown -R root:root /var/www/app && chmod -R a-w /var/www/app
USER www-data
And in Kubernetes:
securityContext:
runAsNonRoot: true
runAsUser: 33
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumeMounts:
- name: uploads
mountPath: /var/www/app/storage
- name: tmp
mountPath: /tmp
Choose the right SAPI
The October advisory singled out mod_php as the highest risk deployment for those flaws, and the 2024 flaw affected PHP running as CGI on Windows. Neither fact means one SAPI is always safe, but the general direction is clear. PHP-FPM behind a separate web server, with pools per site and a Unix socket, gives you more isolation and finer control than PHP loaded inside every Apache process, and far more than php-cgi. If you are still on mod_php or CGI for historical reasons, moving to FPM is a worthwhile project in its own right.
Common mistakes
- Checking
php -von the CLI and assuming the web server runs the same version. Check FPM, Apache modules and each panel site separately. - Trusting
composer.jsonfor the runtime version. It is a constraint. Withconfig.platformset, it can describe a PHP version you do not run anywhere. - Updating packages but not restarting workers. FPM, mod_php and long running workers keep the old binary in memory until restarted.
- Rebuilding the image and not redeploying it. The registry has the fix; production does not.
- Floating base image tags.
php:8-fpmmakes it hard to say which patch version shipped last Tuesday. Pin patch versions and bump them through pull requests. - Counting
disable_functionsandopen_basediras isolation. PHP's manual says both can be bypassed. Use separate users, pools or containers. - Running dozens of plugins nobody owns. Every plugin is a dependency with its own release schedule. Remove what you do not use, and replace what is no longer maintained.
- Leaving end of life planning until the deadline. PHP 8.2 ends on 31 December 2026. A team that starts the upgrade in December will be upgrading during the holidays.
Is our PHP estate in good shape? Ten questions
Use this as a quarterly review. If you can answer yes to all ten with evidence, your PHP estate is in better shape than most.
- Do we have a list of every PHP runtime (host, container image, panel site, managed platform), with version, SAPI, owner and date checked?
- Is every runtime on 8.3, 8.4 or 8.5, or on a distribution with documented backports, with a dated plan for anything on 8.2 or older?
- Could we roll a PHP security release to production within 72 hours? When did we last prove it?
- Do we restart every FPM pool, Apache instance and long running worker as part of that rollout, and verify the new version afterwards?
- Are base images pinned to patch versions and bumped by automated pull requests?
- Does every project have a committed
composer.lock, and does CI runcomposer installfrom it andcomposer audit? - Do we know which Composer packages and CMS plugins are abandoned or unmaintained, and do we have a plan for each?
- Is PHP-FPM reachable only over a Unix socket or an allowlisted address, with one unprivileged user per site?
- Is application code read only at runtime, with uploads stored where PHP will not execute them?
- Is there a named person who decides, during an emergency, whether to patch now, apply a temporary mitigation or take a site offline?
If question 10 makes you uncomfortable, read our post on governments taking sites offline over the PHP flaws. Several organisations had to make that call in hours this week.
Where Safeguard fits a PHP estate
Safeguard scans repositories, container images and SBOM files, including Composer projects, and builds a full transitive inventory. Because the platform shows which projects contain a given component and version, the question "which of our projects still ship this vulnerable package" becomes a lookup rather than a week of grepping. Findings are ranked with reachability, EPSS and CISA KEV status, and Griffin fix pull requests support PHP among other ecosystems, so a Composer bump or a base image change arrives as a reviewable pull request.
What Safeguard does not do: it does not log into your hosting panel, change the PHP version a cPanel site uses, or restart your FPM pools. Bare metal servers and managed platforms still need the runtime inventory steps earlier in this post.
Fix it without waiting for upstream
For PHP estates, the PHP binary itself is fixed by the PHP project and then by your distribution, image or hosting provider, and the steps above are how you roll that out. The rest of your exposure, the Composer packages and container images you build and ship, is where the following applies.
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
FAQ
Is PHP safe to use in 2026?
Yes, on a supported line (8.3, 8.4 or 8.5, or 8.2 until 31 December 2026) with a patch process that can deploy a runtime security release within days. Most PHP breaches come from plugins, packages and application code rather than the interpreter.
Which PHP versions are still supported?
PHP 8.5 and 8.4 are in active support. PHP 8.3 and 8.2 receive security fixes only, and 8.2 reaches end of life on 31 December 2026. PHP 8.1 and older no longer receive fixes from the PHP project.
Is PHP 7.4 still safe to use?
No. PHP 7.4 reached end of life on 28 November 2022. The project published a one off source backport for the October 2026 flaws, but there is no ongoing support. If a distribution or vendor still supports your 7.4 build, get that in writing and plan the upgrade now.
How do I check my PHP version on a server?
Run php -v for the CLI, then check PHP-FPM and Apache separately, for example with ps to find the FPM master and apachectl -M to see if mod_php is loaded. For containers, run php -v inside the image. For hosting panels, check the version selected for each site.
Does updating Composer packages update PHP?
No. Composer manages PHP libraries. The php entry in composer.json is only a constraint. The runtime is updated through your operating system packages, your container base image or your hosting provider.
Is WordPress safe if PHP is patched?
Patching PHP removes interpreter level risk, but most WordPress vulnerabilities are in plugins and themes. One annual report put plugins at 91 percent of new WordPress vulnerabilities in 2025. Keep plugins few, maintained and updated, and remember that WordPress automatic updates do not update PHP itself.
Do disable_functions and open_basedir make PHP secure?
They help, but PHP's own manual says both can be bypassed and should not be relied on as a security boundary. Use separate users, FPM pools, containers and read only code directories for real isolation.
Should we rewrite our PHP application in another language for security?
Usually not. A rewrite takes years and introduces new bugs, while upgrading to a supported PHP line and patching quickly takes weeks. Rewrite for engineering or business reasons if they exist, and keep the PHP system current until the day it is switched off.
How quickly should we apply a PHP security release?
Within 72 hours for a critical release, and the same day when the flaw is remote and needs no login. Then restart every worker that loaded PHP and verify the new version is the one serving traffic.
See how Safeguard would help
The PHP work in this post comes down to two jobs: knowing exactly which PHP projects, packages and images you run, and moving them to fixed versions quickly with a human in control. The demos below show those flows on real sessions. When you are ready to try it on your own code, download the apps at safeguard.sh/download and read the CLI documentation.
This first demo sets up the Safeguard runner on your own machine, approves it with its device code, and then scans from the terminal. For a PHP estate, the same flow lets you scan a Laravel or Symfony repository, or a built container image, locally and get the Composer inventory and findings without uploading anything by hand.
Click through it at your own pace, or open it full screen.
This second demo is a real Safeguard CLI session. You ask it to fix the lodash CVE in a repository; it reads the finding and the advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. The demo uses npm, but the pattern is the one you want for Composer: ask for the fix, approve a targeted composer update and your test run, and review the lock file change before anything leaves your machine.
Click through it at your own pace, or open it full screen.
The third demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. For a PHP team, that means you can ask an assistant which projects still carry a vulnerable Composer package, or which findings are reachable, and get answers from your own Safeguard data rather than a guess.
Click through it at your own pace, or open it full screen.
Quick check
Your composer.json says "php": "^8.3" and composer audit is clean. Are you safe from a PHP interpreter flaw?
Not necessarily. The php constraint does not select or install PHP, and composer audit checks Composer packages, not the runtime. You need to check the actual PHP binaries on each host, container image and hosting panel, and restart workers after updating.
Which hardening control gives real separation between two PHP sites on one server: open_basedir, disable_functions or separate FPM pools running as different users?
Separate FPM pools running as different unprivileged users, ideally in separate containers. PHP's manual describes open_basedir and disable_functions as safety nets that can be bypassed, and notes that even FPM pools share one OPcache instance, so the strongest separation is separate processes or containers.
Sources
- PHP: home page and 21 October 2026 security advisory and releases
- PHP: supported versions
- PHP: unsupported (end of life) branches
- PHP manual: core php.ini directives
- PHP manual: PHP-FPM configuration
- OWASP: PHP configuration cheat sheet
- Composer: command line interface
- Composer: versions and constraints
- Docker Hub: official php image
- Python developer's guide: status of Python versions
- Node.js: previous releases and release lifecycle
- W3Techs: usage statistics of PHP for websites
- Defense One: critical PHP flaws warning (October 2026)
- The Standard: PHP developers issue updates, say flaw was found in 2024
Last reviewed: 23 October 2026. PHP support dates and fixed versions change with each release; check php.net before planning an upgrade.