Drupal security work is normally discussed at the application layer: core advisories, contributed modules, permissions, sanitisation and deployment configuration. The critical PHP security release published on 21 October 2026 is a useful reminder that the application is only as secure as the runtime beneath it. A Drupal site can be fully patched at the Composer level and still be exposed if its PHP workers, command-line runtime or hosting image are running a vulnerable build.
PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 were released to address two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619. The PHP project describes the vulnerabilities as capable of unauthenticated remote code execution and states that updating is the only complete mitigation. ([php.net](https://www.php.net/index.php)) For Drupal teams, the right response is not simply “run Composer update”. It is a coordinated runtime upgrade, application verification and incident-response exercise.
Why this PHP incident matters to Drupal
Drupal is a PHP application, but production Drupal estates frequently contain several PHP runtimes at once:
- PHP-FPM workers serving web requests.
- A command-line PHP binary used by Composer, Drush, cron and deployment jobs.
- Separate PHP versions in staging, CI and local development environments.
- PHP embedded in a managed hosting platform, container image or platform-as-a-service buildpack.
- Long-running queue workers or supervisor-managed processes that do not restart during a normal web deployment.
Updating one of these does not necessarily update the others. A server can report a patched PHP version in an interactive shell while the web server continues to pass requests to an older PHP-FPM pool. Equally, the web tier may be patched while cron still runs using an outdated command-line binary.
This is why runtime security advisories should be treated as infrastructure incidents rather than ordinary dependency updates. The relevant question is not “did Composer change the lock file?” It is “which PHP executable processed each request, and has every execution path been restarted and verified?”
Establish the exposure window
Start by recording facts before changing systems. The PHP release was issued on 21 October 2026, following an advance notice on 20 October. The advance notice rated both vulnerabilities CVSS v4.0 9.2. ([php.net](https://www.php.net/index.php)) Determine when your organisation first deployed a fixed build, then treat the period before that point as the exposure window.
For each environment, record:
- The operating system or container image.
- The PHP version used by web requests.
- The PHP version used by CLI jobs.
- The PHP SAPI in use, such as FPM, Apache module or CGI.
- The Drupal core version and Composer lock-file revision.
- The public and administrative hostnames.
- Whether the site contained sensitive personal, financial or operational data.
- Whether external integrations could create files, invoke webhooks or submit authenticated requests.
Do not assume that a site is safe because it sits behind a CDN or web application firewall. Those controls may reduce exposure, but they do not repair a vulnerable PHP process. They also do not prove that an attacker did not reach the origin through an alternative hostname, a direct IP address, a management interface or an internal integration.
Check every PHP runtime
On a conventional Linux server, begin with the command-line runtime:
php --version
php --ini
command -v php
php -r 'echo PHP_SAPI, PHP_EOL;'
The output identifies the binary available to the current shell, but it does not prove which version serves HTTP traffic. Check the PHP-FPM service and pool configuration separately:
systemctl --type=service --state=running | grep -Ei 'php.*fpm'
systemctl status php8.4-fpm --no-pager
php-fpm8.4 --version
The service name and binary name vary by distribution and installed PHP branch. Do not copy the example literally if your host uses a different package name. On a containerised platform, inspect the image and running container instead:
docker compose exec php php --version
docker compose images
docker compose ps
For Kubernetes, run the equivalent check inside the actual workload rather than inside a developer workstation or build container:
kubectl exec deploy/drupal-php -- php --version
kubectl get pods -l app=drupal-php -o wide
Replace the deployment and label names with those used by your cluster. The important principle is to verify the process that is receiving production traffic.
Upgrade PHP without losing control of the deployment
Use the normal change-management path unless there is evidence of active exploitation. Take a database backup, confirm that file storage is recoverable, record the current package or image versions, and test the replacement runtime against a representative copy of the site.
For distribution-managed PHP, the exact package names depend on the operating system and repository. A Debian or Ubuntu host may use commands similar to the following, but the branch must match the PHP version you intend to run:
sudo apt-get update
sudo apt-get install --only-upgrade php8.4-cli php8.4-fpm php8.4-common
sudo systemctl restart php8.4-fpm
sudo systemctl reload nginx
Do not remove the old PHP branch until you have confirmed that no virtual host, queue worker, cron entry or deployment script still depends on it. On a package-managed system, inspect installed packages and enabled services before making that decision:
dpkg -l | grep -E '^ii php'
systemctl list-unit-files | grep -Ei 'php.*fpm'
grep -R "php[0-9]\.[0-9]" /etc/cron* /etc/systemd/system /etc/supervisor 2>/dev/null
For container deployments, update the base image or PHP image tag, rebuild it, scan it in CI, and redeploy all replicas. Restarting only one task is not enough if a load balancer continues sending traffic to older instances.
FROM php:8.4-fpm-bookworm
RUN docker-php-ext-install opcache pdo_mysql
WORKDIR /var/www/html
The example is deliberately minimal. Drupal’s required extensions and your project’s extensions should come from the project’s documented platform requirements and existing build process. Avoid using a floating image tag such as latest; pin an explicit PHP release or a controlled digest and update it through reviewable configuration.
Restart long-running processes
PHP-FPM workers must be restarted or replaced so that processes loaded from the vulnerable build no longer handle requests. The same applies to queue consumers, Supervisor processes, systemd services and container replicas.
sudo systemctl restart php8.4-fpm
sudo systemctl restart supervisor
sudo systemctl restart drupal-queue-worker.service
Only restart services that exist in your environment. Afterward, confirm process start times and inspect the service logs for failed workers, missing extensions or permission errors:
systemctl show php8.4-fpm --property=ExecMainStartTimestamp
journalctl -u php8.4-fpm --since "15 minutes ago" --no-pager
journalctl -u drupal-queue-worker.service --since "15 minutes ago" --no-pager
Verify Drupal and Composer compatibility
PHP remediation is separate from a Drupal core update, but the two changes should be tested together. Drupal core security updates released on 14 October 2026 included fixes for supported branches, with versions below Drupal 11.4.10, 11.3.19 and 10.6.19 identified as affected by the Canadian Centre for Cyber Security’s summary of the advisories. ([cyber.gc.ca](https://www.cyber.gc.ca/en/alerts-advisories/drupal-security-advisory-av26-1047))
Check the project’s current state before changing dependencies:
composer show drupal/core-recommended --direct
composer check-platform-reqs
git status --short
git log -1 --oneline
If the Drupal core update is outstanding, use the project’s existing dependency strategy. A common Composer-managed Drupal project uses:
composer update "drupal/core-*" --with-all-dependencies
drush updatedb -y
drush cache:rebuild
drush config:status
Review the resulting changes carefully. Do not blindly accept unrelated package upgrades during an emergency patch. If the lock-file diff is unexpectedly large, stop and split the changes into a controlled PHP remediation deployment and a separate dependency maintenance change.
After deployment, run Drupal’s status and integrity checks where available:
drush status
drush core:requirements
drush config:status
drush cache:rebuild
drush core:requirements can reveal missing or unsuitable PHP extensions, while drush config:status helps identify configuration drift between the deployed codebase and active configuration. These checks do not detect compromise, but they are useful for distinguishing an upgrade problem from a security problem.
Verify the version that actually serves requests
A frequent operational mistake is verifying only the CLI version. The safest verification is an authenticated, temporary diagnostic endpoint or an equivalent platform health check that reports the runtime without exposing unnecessary server information publicly.
If you create a diagnostic endpoint, protect it with network controls or authentication and remove it immediately after testing. Do not publish phpinfo() on a public site. It can disclose filesystem paths, environment variables, loaded modules and server configuration.
For a short-lived internal check, a Drupal route or health-check implementation should return only the minimum required information, such as the PHP major and minor version, and should be restricted to trusted operators. An even better production pattern is to emit the runtime version to internal telemetry during application bootstrap and compare it with the approved deployment inventory.
Also test a real web request through the normal proxy chain:
curl --head --fail https://www.example.org/
curl --silent --show-error --fail https://www.example.org/user/login > /dev/null
These requests do not reveal the PHP version by themselves, but they confirm that the origin remains available after the PHP-FPM restart. Pair them with your host, container or service-level version check.
Perform a proportionate compromise assessment
Because the vulnerabilities allow unauthenticated remote code execution, patching alone may not be sufficient if the environment was exposed for a meaningful period. The PHP project states that there are no complete mitigations other than updating. ([php.net](https://www.php.net/index.php)) After containment, review logs for suspicious activity during the exposure window.
Prioritise:
- Web server access and error logs.
- PHP-FPM logs and process-manager logs.
- WAF, CDN, load-balancer and origin firewall logs.
- Drupal watchdog records and authentication logs.
- Unexpected changes to
settings.php, service files, cron entries and deployment scripts. - New PHP files or executable files in public, temporary and upload directories.
- Changes to administrator accounts, roles, API keys, OAuth clients and webhook credentials.
- Unexpected outbound connections from web and queue-worker hosts.
Search for recently modified files, but treat the result as a lead rather than proof:
find web/sites web/modules web/themes web/libraries \
-type f -mtime -14 -printf '%TY-%Tm-%Td %TH:%TM %p\n' \
| sort
Also review executable files in locations that should contain user-uploaded data. The exact paths differ between projects, so first inspect Drupal’s file configuration and deployment layout rather than assuming that every site uses web/sites/default/files.
Do not edit or delete suspicious files before preserving evidence. If the site handles regulated or sensitive data, involve your incident-response provider, hosting company and data-protection lead. Rotate secrets from a trusted environment, not from a potentially compromised server. That includes database credentials, Drupal hash salts, cloud credentials, deployment keys, SMTP passwords, third-party API tokens and webhook signing secrets.
PHP 8.2 requires a second decision
PHP 8.2.35 contains the October security fixes, but the PHP project states that PHP 8.2 reaches end of life on 31 December 2026 and will receive no further security fixes after that date. ([php.net](https://www.php.net/index.php)) This makes the immediate patch and the platform upgrade two different work items.
For a site currently running PHP 8.2, the sensible sequence is:
- Upgrade immediately to the fixed PHP 8.2.35 build or the fixed package supplied by your platform.
- Confirm Drupal and contributed modules operate correctly.
- Open a tracked upgrade task for PHP 8.3, 8.4 or another supported branch compatible with the site.
- Test the target branch in staging with production-like traffic and queue workloads.
- Deploy before the 31 December 2026 end-of-life date.
Do not jump directly to a pre-release PHP build on production merely to avoid the end-of-life deadline. PHP 8.6.0 RC4 was available for testing on 21 October 2026, but the PHP project explicitly stated that it should not be used in production. ([php.net](https://www.php.net/archive/2026.php/)) Production should use a supported stable branch that Drupal and the project’s dependencies officially support.
Improve the Drupal patching runbook
The October events also expose weaknesses in many patch processes. Drupal’s own security team reported a substantial increase in advisory volume between June and October 2026, with 256 advisories published during the period covered by its Drupal AI Security Initiative update. ([drupal.org](https://www.drupal.org/blog)) Whether or not that rate continues, teams should assume that security work will arrive across the full stack: Drupal core, contributed modules, PHP, web servers, operating systems, container images and external services.
A practical runbook should include the following controls:
- Runtime inventory: record the PHP version for every web, CLI, worker and CI environment.
- Patch ownership: assign responsibility for Drupal, PHP packages, base images and hosting-platform updates separately.
- Fast-path changes: maintain a pre-approved process for critical security updates that still records testing and approval.
- Reproducible builds: commit Composer lock files and pin container or package sources where possible.
- Health checks: verify application responses, queues, cron, search, email and integrations after runtime changes.
- Exposure assessment: define when a patched vulnerability also triggers log review, secret rotation or formal incident response.
- Rollback planning: know how to restore the previous application release without rolling back to a vulnerable runtime.
Separate application and infrastructure checks in CI
Composer can enforce a minimum PHP version, but it cannot prove that production is running the version declared in the project. Add both checks to the deployment pipeline:
php --version
composer validate --strict
composer check-platform-reqs
vendor/bin/drush status --fields=drupal-version,php-version
The final command assumes Drush is installed as a project dependency and that the installed Drush version supports the requested fields. If it does not, use the normal drush status output and parse it in a deployment-specific health check rather than adding an untested flag.
At the infrastructure layer, enforce the approved PHP version in the image build, package repository or hosting configuration. At the runtime layer, alert when a web pool, queue worker or CLI job reports a version outside the approved range. This turns a future emergency from a manual inventory exercise into a measurable deployment policy.
Do not mistake availability for safety
A Drupal site that returns HTTP 200 after a PHP update is not necessarily secure. Availability checks confirm that the application is responding; they do not confirm that all workers were replaced, that secrets were not stolen, or that a malicious persistence mechanism was not installed during the exposure window.
The correct completion criteria are broader:
- All PHP execution paths run a fixed supported release.
- All vulnerable workers and replicas have been replaced.
- Drupal core and relevant contributed projects are within supported security ranges.
- Application behaviour, cron, queues and integrations have been tested.
- Logs have been reviewed for the exposure period.
- Credentials have been rotated where compromise cannot be ruled out.
- The deployment record contains the versions, timestamps and verification results.
- A follow-up task exists for PHP 8.2 migration if the site still uses that branch.
Conclusion
The October 2026 PHP vulnerabilities are a strong example of why Drupal security cannot be managed solely through the Drupal admin UI or Composer. The vulnerable component may sit below the application, be duplicated across several runtimes and remain active in long-running workers after a package installation appears successful.
Patch the PHP runtime first, verify the actual processes serving production traffic, update Drupal where required, and then assess whether the exposure window warrants incident response. For teams still using PHP 8.2, treat the fixed 8.2.35 release as an emergency bridge rather than a long-term destination: the branch reaches end of life on 31 December 2026. A reliable Drupal operation is not one that never encounters a critical advisory; it is one that can identify every affected execution path, deploy a controlled fix and produce evidence that the fix is complete.
Sources and further reading
- PHP project release announcements for PHP 8.2.35 through 8.5.12 and the associated critical vulnerabilities. ([php.net](https://www.php.net/index.php))
- Drupal security advisory listings, including the October 2026 core and contributed-project advisories. ([drupal.org](https://www.drupal.org/security/p))
- Canadian Centre for Cyber Security summary of the October 2026 Drupal core updates. ([cyber.gc.ca](https://www.cyber.gc.ca/en/alerts-advisories/drupal-security-advisory-av26-1047))
- Drupal’s October 2026 update on advisory volume and the Drupal AI Security Initiative. ([drupal.org](https://www.drupal.org/blog))