TL;DR
- PHP2Shell is two critical bugs in the PHP engine: CVE-2026-109618 (RCE via out-of-memory corruption) and CVE-2026-109619 (RCE via stale global state). Both are rated CVSS v4.0 9.2 and both allow unauthenticated remote code execution as the web worker account.
- The bugs live below your application. A "Hello World" page on an affected PHP version can be vulnerable, and researchers demonstrated unauthenticated RCE against current WordPress, Drupal, Joomla and Magento builds.
- The fix is upgrading PHP to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 (released 21 October 2026). PHP's own words: "There are no complete mitigations, updating is the only safe choice." PHP 8.1 and older get only minimal source backports from the PHP project.
- Salesforce core (Sales Cloud, Service Cloud, Experience Cloud, Apex, Flow) does not run your PHP. Salesforce's Trust notice says it has "no evidence of exploitation affecting Salesforce or customer data."
- Heroku has shipped patched PHP runtimes. Your app does not pick them up until you redeploy.
- The Salesforce risk worth your time is credentials held by PHP sites: a WordPress lead plugin, a Drupal portal, a Magento sync, a custom PHP integration. If one of those was unpatched and on the internet after 20 October, rotate its Salesforce credentials and check the integration user's login history. Updating the plugin or connector does not help; the fix is the PHP underneath it.
What You'll Learn
- What the two PHP2Shell bugs are, in plain terms, and why patching your application code does nothing for them
- Which PHP versions are fixed, and how to confirm the version serving web requests
- The interim settings that narrow the attack if you cannot patch today, and why they are not a fix
- Exactly where Salesforce is and is not exposed: core platform, Heroku, and connected PHP systems
- A credential rotation and log review checklist for any PHP system that talks to your org
The Problem
On 20 October 2026 the PHP project announced an unscheduled critical security release for the following day. Details had already started leaking on social media, and by the time the patches shipped at 14:00 UTC on 21 October, Cloudflare had reported attack traffic as early as 07:43 UTC that morning, according to Sansec's timeline. Amazon Threat Intelligence later reported an exploitation attempt against its MadPot honeypots on 17 October, four days before disclosure. Kevin Beaumont called it "one of the biggest vulns in years."
The reason for the noise is where the bugs sit. Most web vulnerabilities live in a plugin, a framework or a specific endpoint, so the question is "do we run that thing?" PHP2Shell lives in the PHP runtime, which serves WordPress, Drupal, Magento, Joomla, MediaWiki, Laravel, Symfony and most shared hosting on the internet. The question becomes "do we run PHP anywhere?", and for most organisations the honest answer is "probably, somewhere we forgot about."
For a Salesforce team, the first reaction is often "we're on Salesforce, this isn't ours." That is mostly true for the platform and mostly false for the edges of it. The marketing site with a lead capture plugin, the partner portal someone built in Laravel in 2019, the Heroku app that syncs orders: those are PHP, and many of them hold a credential that can log in to your org.
Common questions this article answers:
- Does PHP2Shell affect my Salesforce org directly?
- We have a WordPress site that sends leads to Salesforce. What do I need to do?
- If a PHP server that connects to my org was compromised, how do I find out and what do I rotate?
Quick Answer
Upgrade every PHP installation that serves web requests to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35, then restart PHP-FPM or Apache so the old workers die. Check the version the web server is using, not just php -v on the command line, because they can be different binaries. If you are on Heroku, redeploy each PHP app to pick up the patched runtime. If you cannot patch today, set session.upload_progress.enabled = Off (and fatal_error_backtraces = Off on PHP 8.5), block multipart/form-data at your web server or WAF if the site does not take uploads, or take the site offline; none of these is a complete fix. For Salesforce: the core platform needs nothing from you, but any PHP system holding Salesforce credentials that was unpatched and internet facing after 20 October should be treated as possibly compromised. Patch it first, then rotate the connected app or external client app secret, revoke the integration user's OAuth tokens, replace any JWT certificate whose private key lived on that server, and review the integration user's Login History for unfamiliar IP addresses.
What PHP2Shell is
Two CVEs cover the family. Wiz Research found the bugs in August 2026, using AI models to help build working exploits, and reported them to PHP on 24 August. Wiz's write up says the flaws had existed for more than a decade and that "Frontier AI models substantially reduced that barrier, turning a longstanding flaw into an exploit."
CVE-2026-109618: RCE via out-of-memory corruption
When PHP runs out of memory, it does not unwind politely. It jumps straight out of whatever it was doing (a C longjmp(), which PHP calls a bailout) and heads for request shutdown. The PHP advisory explains that in some places, request memory is reachable before it is fully set up. If an allocation fails at that moment, shutdown "may then read or branch on" memory that was never initialised.
The attacker does not need a memory leak in your code. The advisory lists ways to make PHP run out of memory while it is still parsing the request body, before your application has started:
- multipart requests without a usable declared length can slip past the initial
post_max_sizecheck - multipart parts can carry an unlimited number of headers, which cost far more memory inside PHP than on the wire
- empty file fields do not count towards
max_file_uploadsbut still create metadata, and nested field names multiply that
Sansec also reports that this bug can leak process memory, which may include passwords, session tokens, API keys and TLS private keys.
CVE-2026-109619: RCE via stale global state
PHP workers are reused. An Apache prefork child or a PHP-FPM worker serves one request, cleans up, and serves the next. Some global state (error, session and extension state) can point at memory that belongs to a single request. That pointer must be reset before the request's memory is freed. A fatal error or timeout can skip the reset, and the next request handled by the same worker can read the stale pointer before PHP reinitialises it. That is a use-after-free.
Two "consumers" that read the stale state early are confirmed: INI diagnostics raised while applying per-directory settings, and session upload progress, which runs while PHP is still parsing a multipart upload. That second one is why session.upload_progress.enabled = Off appears in every workaround list.
Which setups are hit hardest
The advisories split the risk by how PHP is wired into the web server:
| Setup | CVE-2026-109618 | CVE-2026-109619 |
|---|---|---|
| Apache with mod_php | Confirmed RCE over HTTP with default limits | Confirmed |
| PHP-FPM (nginx or Apache) | Partial; no complete FPM exploit demonstrated | Conditional; session upload progress case validated |
| FrankenPHP | Likely by source analysis, not validated | No early consumer found by default, "does not make it immune" |
| LiteSpeed (LSAPI) | Likely, not validated | Conditional |
An exploit nobody has demonstrated yet can still exist, so patch all of them.
How to fix it
Step 1: find every PHP that serves web traffic
The inventory is the hard part. Look beyond the obvious:
- marketing sites and blogs (WordPress, Drupal, Joomla)
- e-commerce (Magento, WooCommerce, Shopware)
- internal tools (phpMyAdmin, Nextcloud, MediaWiki, Roundcube, WHMCS)
- Heroku apps using the PHP buildpack
- container images with PHP baked in (check base image tags)
- managed WordPress or shared hosting accounts that someone in marketing pays for
Step 2: check the version the web server runs
On a server, php -v tells you about the command line binary. The web server may run a different one. Check each:
# Command line PHP
php -v
# PHP-FPM (the binary name varies by distribution, for example php-fpm8.3)
php-fpm -v
# Apache with mod_php on Debian or Ubuntu: list the loaded PHP module
apache2ctl -M | grep -i php
The safest check is to ask the web server itself. Create a temporary file in the web root containing <?php echo PHP_VERSION;, load it in a browser, note the version, and delete the file immediately.
For WordPress, an admin can read the version without a terminal: Tools, then Site Health, then the Info tab, then Server.
Step 3: upgrade and restart
Install the fixed version from your distribution or LTS vendor; they received patches before the public release. Then restart so every old worker is replaced:
# Debian or Ubuntu with PHP-FPM (adjust the version)
sudo apt update && sudo apt install --only-upgrade php8.3-fpm php8.3-cli
sudo systemctl restart php8.3-fpm
# Apache with mod_php
sudo systemctl restart apache2
Re-run the version check from Step 2 afterwards. A package upgrade without a restart leaves the vulnerable code in memory.
If you use the Remi repository on RHEL-family systems, Help Net Security reported that Remi had no updated packages on release day and advised switching to distribution packages or building from source. Check its status before assuming a dnf update fixed anything.
Step 4: if you cannot patch today
These narrow the attack. PHP's advisories are explicit that they are not complete:
; php.ini (then restart all workers)
session.upload_progress.enabled = Off
; PHP 8.5 only: removes the producer for the confirmed CVE-2026-109619 RCE path
fatal_error_backtraces = Off
Other options, in rough order of cost:
- Turn on your WAF rules. Cloudflare deployed rules for known exploit vectors and said they are available to all customers, including free plans. Imperva, Fastly, Vercel and Google have published protections or guidance too.
- Block
multipart/form-dataat the web server if the site never takes uploads. This breaks file uploads and some forms, so test a checkout or contact form afterwards. - Allow only GET and HEAD to make a site read only for a few hours.
- Take it offline. The UK NCSC has urged organisations to consider this for systems they cannot fix right away.
PHP recommends keeping session.upload_progress.enabled = Off even after patching if you do not use the feature. Most sites do not.
The Salesforce impact
There are three different answers depending on which part of Salesforce you mean.
Salesforce core platform: nothing for you to patch
Your org runs Apex, Flow, Lightning Web Components and Visualforce. None of that is PHP, and you cannot deploy PHP to a Salesforce org. Web-to-Lead and Web-to-Case forms post straight to Salesforce, so the form handler is not PHP either (the page hosting the form might be, which is covered below).
Salesforce posted an informational Trust notice on 21 October 2026 titled "Security Advisory: PHP Vulnerabilities (CVE-2026-109618 and CVE-2026-109619)." It reads: "Salesforce is aware of and actively monitoring the PHP vulnerabilities (CVE-2026-109618 and CVE-2026-109619) and related activity. At this time, we have no evidence of exploitation affecting Salesforce or customer data." That is a statement about Salesforce's own infrastructure. It says nothing about the PHP systems you connect to your org.
Heroku: patched runtimes, but only after you redeploy
Heroku is part of Salesforce, and PHP is one of its supported languages. Heroku released PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 on 21 October 2026, along with updated Apache (2.4.69) and nginx (1.30.6). The changelog is direct: "Redeploy your apps to pick up the fixed versions."
A running dyno keeps the PHP it was built with. To pick up the fix:
# Check which PHP the running app is using
heroku run "php -v" -a your-app-name
# Trigger a rebuild without code changes
git commit --allow-empty -m "rebuild for php security release"
git push heroku main
Then run heroku run "php -v" again. If your composer.json pins an exact PHP version (for example "php": "8.3.30"), the rebuild keeps that old version. Change the constraint to a range such as "php": "^8.3" so the buildpack can resolve the patched release.
PHP 8.1 is end of life. Heroku rebuilt PHP 8.1.34 on the Heroku-22 stack with the PHP project's backported fix, and describes it as "a minimal mitigation rather than a supported release." If you are on 8.1, this is the push to upgrade.
Salesforce connectors and plugins that run on PHP
None of these plugins or libraries contains the PHP2Shell bug. The bug is in the PHP runtime underneath them, so updating the plugin does nothing; only a PHP upgrade on the host fixes it. What the plugin decides is what an attacker walks away with once they have code execution. These are the common ones to look for:
| Tool | Runs on | How it connects to Salesforce | What sits on the server |
|---|---|---|---|
| Account Engagement (Pardot) plugin for WordPress | WordPress | Connected app with the refresh_token scope, authorised by an admin through Salesforce SSO |
Consumer key and secret, Business Unit ID and the resulting tokens, in plugin settings (the plugin encrypts stored strings) |
| Object Sync for Salesforce (MinnPost) | WordPress | Connected app | Connected app credentials and tokens |
| Object Data Sync for Salesforce | WordPress (WooCommerce, Gravity Forms, WPForms, Ninja Forms, Contact Form 7) | Connected app, plus an AppExchange package for sync back to WordPress | Connected app credentials and tokens |
| Form plugin Salesforce add-ons (Gravity Forms and others) | WordPress | Varies by add-on; older ones use Web-to-Lead or a username and password | Anything from nothing (Web-to-Lead) to a full integration login |
| Salesforce Suite module | Drupal | Pluggable auth; the JWT bearer provider is the recommended one | The JWT private key, wherever the site keeps it |
| omniphx/forrest | Laravel and Lumen apps | Web server OAuth flow or username and password, set in config/forrest.php |
Consumer key, secret and possibly username and password in .env |
| Force.com Toolkit for PHP | Custom PHP | SOAP login with username, password and security token | Integration user password and token in code or config. The repository is archived and marked unsupported |
| FuelSDK-PHP | Custom PHP talking to Marketing Cloud | Marketing Cloud installed package client ID and secret | Client ID and secret. The official package is marked abandoned on Packagist |
Magento and WooCommerce stores connected to Salesforce through a commercial connector belong in the same bucket: the connector itself is fine, and the credentials it stores are the exposure.
Two quick ways to find these from the Salesforce side, without knowing who built what:
- In Setup, open Connected Apps OAuth Usage. An app named after a website, a CMS such as WordPress or Drupal, or the agency that built your site usually points at a PHP system.
- In Login History, filter by your integration users and look at the Application and Source IP columns. A login from a web host's IP range is usually a website.
On managed WordPress hosting, you cannot upgrade PHP yourself. Check your host's status page for its PHP2Shell rollout, and do not assume a "PHP 8.3" label means 8.3.36.
Where you are exposed: PHP systems that hold your Salesforce credentials
Spend your afternoon here. PHP2Shell gives an attacker code execution as the web worker account, and CVE-2026-109618 can also disclose process memory. On a PHP site that integrates with Salesforce, that account can usually read:
- a
.envfile orwp-config.phpwith a connected app or external client app consumer key and secret - a stored refresh token in the database or plugin settings
- an integration user's username, password and security token, used by older plugins and the retiring username-password OAuth flow
- the private key for a JWT bearer flow, sitting on disk next to the code
- Marketing Cloud API client IDs and secrets used by the same site
Any of these lets an attacker call your org's API as the integration user, with whatever access that user has. If the integration user has View All Data, the attacker has it too.
Use this rule: if a PHP system that holds Salesforce credentials was internet facing and unpatched at any point after 20 October 2026, assume the credentials are exposed. Patch first (otherwise the attacker can read the new credentials straight back), then work through the checklist below.
Credential rotation and log review checklist
Do these in order, after the PHP system is patched.
1. Find the integration user and the app. In Setup, open Connected Apps OAuth Usage to see which apps hold tokens and for which users. For an external client app, check External Client App Manager.
2. Revoke the integration user's OAuth tokens. In Setup, open Users, select the integration user, scroll to OAuth Connected Apps, and click Revoke next to each app. The PHP system will need to reauthorise afterwards.
3. Rotate the consumer secret. For a connected app, open App Manager, find the app, click View, then Manage Consumer Details, and generate a new secret. Put the new value into the patched system.
4. Replace the JWT certificate if the private key lived on the PHP server. Generate a new key pair somewhere other than the web root, upload the new certificate to the app, and remove the old one.
5. Reset the integration user's password and security token if the site used username and password authentication. While you are there, plan the move off that flow; see Salesforce Retires the OAuth Username-Password Flow on 20 February 2027.
6. Review the integration user's logins. In Setup, open Login History and filter to the user, or query it with the Salesforce CLI. This query shows every login for one user since the leak, newest first:
sf data query --target-org my-org --query "SELECT LoginTime, SourceIp, Status, Application, LoginType FROM LoginHistory WHERE UserId = '005XXXXXXXXXXXXXXX' AND LoginTime >= 2026-10-20T00:00:00Z ORDER BY LoginTime DESC"
Replace my-org with your org alias and 005XXXXXXXXXXXXXXX with the integration user's Id. You are looking for source IP addresses that are not your PHP server's address. An integration user should log in from a small, predictable set of IPs, so anything else stands out.
7. Check API activity if you have Event Monitoring. API and Login event log files show what the integration user queried and from where. Why Filtering Salesforce Event Logs by IP Misses Most of the Incident walks through correlating them. If you only have the free daily log files, the free EventLogFile baseline covers what you can still see.
8. Restrict the integration user going forward. Set login IP ranges on its profile to the PHP server's addresses, and trim its permissions to what the integration really uses. Which of Your Salesforce Connected Apps Use Less Than They're Granted? shows how to measure that gap.
Troubleshooting
The site still reports the old PHP version after upgrading. The web server is still running old workers, or it loads a different PHP than the one you upgraded. Restart PHP-FPM and Apache, then check again with a PHP_VERSION page, not php -v.
The Heroku rebuild kept the old version. Your composer.json or composer.lock pins an exact PHP version. Loosen the constraint, run composer update --lock locally, commit both files, and push again.
The integration broke after revoking tokens. That is expected. The PHP system needs to reauthorise with the new consumer secret or certificate. For plugins, this is usually a "Connect to Salesforce" button in the plugin settings.
Login History shows unknown IPs but the integration runs through a proxy or CDN. Some hosting platforms use rotating egress addresses. Ask the host for its published egress ranges before you conclude it was an attacker, and check the Application column; an attacker using stolen credentials often shows a different client name from the plugin's own.
I cannot patch because the app needs PHP 7.4. The PHP project published minimal source backports for 7.4, 8.0 and 8.1, intended for source builds or users without an LTS vendor. Commercial LTS vendors also ship patched builds. Treat this as temporary, apply the Step 4 settings, and put the site behind a WAF while you plan the upgrade.
Frequently Asked Questions
Is my Salesforce org vulnerable to PHP2Shell?
Not directly. Salesforce orgs do not run customer PHP, and Salesforce's Trust notice reports no evidence of exploitation affecting Salesforce or customer data. Your exposure comes from PHP systems outside the org that hold credentials to it, and from PHP apps on Heroku that you have not redeployed.
Has PHP2Shell been exploited in the wild?
There have been attempts, but no confirmed break-ins have been made public yet. Amazon Threat Intelligence saw a PHP2Shell attempt against its MadPot honeypots on 17 October 2026, four days before disclosure, and says the vulnerabilities are "now seeing broad exploitation attempts in the wild." Amazon also says "it's unclear if any of these attempts would have succeeded in real-world systems." watchTowr reports exploitation observed in the wild since 21 October, and Cloudflare reported attack traffic before the patch was released. On the other side, Sansec's 22 October update says mass exploitation "is less likely than we expected on release day" because "an attack needs specific knowledge of the target server and specific conditions on it." PHP's own advisory, however, validated RCE against mod_php with default input and memory limits. On 23 October 2026 neither CVE was on CISA's Known Exploited Vulnerabilities list. Plan as if exploitation is happening.
Our WordPress site uses a plugin to send leads to Salesforce. What should I do?
Patch the site's PHP first, or ask your host to confirm they have. Then check how the plugin authenticates. If it stores a username, password and security token, or a consumer secret and refresh token, and the site was unpatched after 20 October, rotate those credentials and review the integration user's Login History using the checklist above.
Do the php.ini workarounds protect me?
They cut off specific demonstrated attack paths. PHP's advisories say updating is the only complete mitigation, and Wiz notes that other untracked variants likely exist. Use the settings to buy hours, not weeks.
Do I need to update my WordPress Salesforce plugin?
Updating the plugin will not fix PHP2Shell, because the bug is in PHP itself. Upgrade PHP on the host (or confirm your host has), then treat the plugin's stored Salesforce credentials as exposed if the site was unpatched after 20 October. Keep the plugin updated anyway; it just is not the fix here.
Does Marketing Cloud or Commerce Cloud run PHP?
Marketing Cloud CloudPages use AMPscript and server-side JavaScript, and Commerce Cloud B2C uses server-side JavaScript. Neither runs customer PHP. A Magento or WooCommerce store connected to Salesforce, however, does run PHP and falls under the credential checklist.
Key Takeaways
- PHP2Shell is two engine-level bugs (CVE-2026-109618 and CVE-2026-109619) that allow unauthenticated RCE before your application code runs.
- The only complete fix is PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35, followed by a restart. Check the web server's PHP, not only the command line.
- Interim settings (
session.upload_progress.enabled = Off,fatal_error_backtraces = Offon 8.5) and WAF rules narrow the attack; they do not close it. - Salesforce core needs no action. Heroku PHP apps need a redeploy.
- Any PHP system holding Salesforce credentials that was unpatched after 20 October should be patched, then have its credentials rotated and its integration user's logins reviewed.
What's Next?
Recommended reading:
- Which of Your Salesforce Connected Apps Use Less Than They're Granted? Ask Your Own Logs
- Why Filtering Salesforce Event Logs by IP Misses Most of the Incident
- Migrating Connected Apps to External Client Apps: The Tool Now Covers Packaged and Distributed Apps
- Salesforce Retires the OAuth Username-Password Flow on 20 February 2027
Action items:
- List every PHP system your organisation runs, including marketing sites and Heroku apps, and record its PHP version as served by the web server.
- Patch and restart each one, or apply the interim settings and WAF rules today if you cannot.
- Redeploy every Heroku PHP app and confirm the new version with
heroku run "php -v". - For each PHP system that holds Salesforce credentials, decide whether it was exposed after 20 October. If yes, run the rotation and log review checklist.
- Add login IP ranges to every integration user's profile so a stolen credential cannot be used from anywhere else.
Resources & References
- PHP security advisory and release announcements (21 October 2026)
- GHSA-w8hw-w9fx-j79w: RCE via OOM corruption (CVE-2026-109618)
- GHSA-6wmf-4rv5-p3rp: RCE via stale global state (CVE-2026-109619)
- Wiz Research: PHP2Shell
- Salesforce Trust: Security Advisory, PHP Vulnerabilities
- Heroku changelog: PHP updates, October 2026
- Account Engagement plugin for WordPress
- Object Sync for Salesforce (MinnPost)
- Object Data Sync for Salesforce
- Drupal Salesforce Suite
- omniphx/forrest on Packagist
- Force.com Toolkit for PHP on Packagist
- FuelSDK-PHP on Packagist
- Amazon Threat Intelligence: PHP2Shell exploitation prior to public disclosure
- Sansec: PHP2Shell research and timeline
- Imperva: PHP2Shell, when PHP runs out of memory at the wrong moment
- watchTowr: PHP2Shell FAQ
- Help Net Security: PHP2Shell patched, update now
- SecurityWeek: PHP2Shell, mass exploitation looms
Responses
Checking your session.
Loading responses.