Skip to main content
Security incident analysis
セキュリティ
脆弱性診断
PHP
インフラ
アーキテクチャ設計
信頼性

PHP2Shell (CVE-2026-109618 and CVE-2026-109619) Explained: Two Different Bugs, the Invariants the Patch Restores, and What Operators Should Check Today

PHP2Shell (CVE-2026-109618 and CVE-2026-109619) explained from the official advisories and the fix commit: how the two CVEs differ, status by SAPI, fixed versions, the limits of mitigations, how to check your own exposure, and how CVE-2026-115560 relates.

Published
Reading time
20 min read
Author
友田 陽大
Share

On 21 October 2026 the PHP project released fixes for two critical vulnerabilities that can lead to unauthenticated remote code execution (RCE). The researchers who found them nicknamed the pair "PHP2Shell". Because so much of the web runs on PHP, the potential reach is large.

This article answers three questions:

  • Is my service affected, and what should I check first?
  • How do the two vulnerabilities differ, and why can they allow code to run remotely?
  • Which program rule that was being broken did the fix restore?

Scope. No attack code or procedure is included — only what the official advisories and the fix commit let you understand about the mechanism, plus defenses. The C examples are independent teaching code for the same class of bug and are not a reproduction of PHP2Shell. Information reflects primary sources as of 1 November 2026 (JST).

Key points in 30 seconds

  • There are two vulnerabilities, and they are different. CVE-2026-109618 (out-of-memory handling corrupts internal state) and CVE-2026-109619 (stale state from a previous request survives).
  • Fixed versions: PHP 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 (released 21 October 2026). PHP 8.1 and older are outside the PHP project's updates.
  • They are being exploited: CISA added both to its Known Exploited Vulnerabilities catalog on 26 October.
  • Highest-risk runtime: Apache mod_php, where an attack has been demonstrated to succeed right after a request is accepted, before any application code runs.
  • Configuration mitigations are incomplete. The vendor states plainly that updating is the only complete fix.
  • Check: the PHP version your web server runs (not the CLI), whether your OS vendor has taken the fix, any end-of-life version, and signs of compromise.

Before you hold real customer data

Web app & SaaS security audit — authorization, tenant isolation and config, verified in the code

Facts confirmed in official sources

ItemContentSource
Published21 October 2026 (fixed releases and advisories)php.net, GitHub Security Advisories
CVE-2026-109618"RCE via OOM corruption": out-of-memory (OOM) handling corrupts partly initialized internal stateGHSA-w8hw-w9fx-j79w
CVE-2026-109619"RCE via stale global state": internal state that survives across requests is usedGHSA-6wmf-4rv5-p3rp
SeverityBoth GHSAs are "critical". CVSS v4.0 base score is 9.2 for both (AV:N/AC:H/AT:P/PR:N/UI:N)both GHSAs
Weakness typeCWE-416 (use after free) among others; both carry the same classificationboth GHSAs
Fixed versions8.2.35, 8.3.36, 8.4.27, 8.5.12 (anything earlier in that branch is affected)both GHSAs, php.net
ExploitationOn CISA KEV since 2026-10-26 (due 10-29). Use in ransomware: "unknown"CISA KEV
DiscoverersResearchers at Calif, OpenAI and Wiz are credited as reporters in the GHSAsboth GHSAs

Three notes on reading these:

  1. The scores are CVSS v4.0. In the GHSAs the author checked, no v3.x score is attached. If you see a v3.1 score elsewhere, check the source and who scored it.
  2. "High attack complexity" (AC:H) does not mean "safe". It reflects a dependence on memory layout; demonstrations and observed exploitation both exist.
  3. How it was found: according to the researchers' write-up, a memory-limit issue was reported in 2020 and rediscovered in a 2024 external audit, but it was not fixed because exploitation had not been shown. It illustrates how hard it is to decide on "fix only once exploitability is proven".

Status by runtime (SAPI): separate "demonstrated" from "can be affected"

The most important thing in reading the two CVEs is how the situation differs by runtime. The GHSAs' statements, as a table:

RuntimeCVE-2026-109618 (OOM)CVE-2026-109619 (stale state)
Apache mod_phpDemonstrated. Unauthenticated RCE over HTTP validated against prefork setups with near-default settings; succeeds before application code runsDemonstrated (the PHP 8.5 fatal-error backtrace path and the session upload-progress path)
PHP-FPMIf request startup fails the child exits, so that path is hard to use. Post-startup paths are susceptible per source analysis, but no complete FPM attack has been demonstratedThe session upload-progress path was validated on FPM too, depending on an application operation. INI-setting paths are reachable conditionally, only when the frontend passes PHP_VALUE
FrankenPHPLike mod_php it calls request shutdown unconditionally, so it is likely susceptible (source analysis)No early reachable path found in the default configuration; that is not immunity
LSAPI (LiteSpeed)Resembles FPM; application-specific attacks are likely but unvalidatedA conditional candidate via environment-supplied INI values
CLIThe advisories do not address the CLI (author's inference: no web input path, so mostly out of scope — but update it wherever the same PHP also serves the web)same

The PHP project says the exposed population is "all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed", and rates mod_php as highest risk.

Background: how PHP handles a request

A hotel housekeeper

A PHP worker (the process that handles requests) is like a hotel housekeeper.

  1. A guest arrives (a request starts)
  2. The housekeeper prepares a room for that guest (allocates memory for that request)
  3. The guest's needs are handled (PHP code runs)
  4. When the guest leaves, the room is cleaned and reset for the next guest (request shutdown)

The key point: one housekeeper serves many guests in turn. The housekeeper keeps notes (global state) that survive from one guest to the next. If a note still says "the key to room 3 is here" after room 3 has been demolished, the next guest arrives and the housekeeper acts on a key to a room that no longer exists.

The two PHP2Shell vulnerabilities are two different forms of this "cleanup failure":

  • 109619: after a guest leaves, a note still points at the demolished room and gets used before the next guest is prepared
  • 109618: an emergency stop hits partway through preparing a room, and the cleaner then works as if "everything is in place" in a half-furnished room

Terms

  • Zend Engine: the core of PHP. It interprets PHP code and also manages memory.
  • Request lifecycle: start-up → execution → shutdown.
  • OOM (out of memory): in PHP this happens when memory_limit (default 128M) is exceeded.
  • longjmp: a C mechanism that jumps straight from where you are to a designated point far away. The rest of every function in between is not run. PHP used it to abort processing on errors.
  • Use after free: reading or writing freed memory as if still valid. If an attacker can influence what the memory was reused for, the program's behavior can potentially be taken over.

Why longjmp differs from normal control flow

Normally, when a function finishes, it runs its cleanup code (for example "release the memory I allocated", "restore the state") before returning to its caller.

function A → function B → function C
         ↑ C finishes → B cleans up → A cleans up   (normal)

function A → function B → function C ── longjmp ──▶ a safe point outside A
                          (the cleanup of B and C is skipped entirely)

A longjmp skips the cleanup of every function it jumps over, so the program's internal state is left mid-way. If something reads that mid-way state later, there is a problem.

The invariants that were broken

An "invariant" is a rule that should hold at every point in the program. For example: "in a linked list, every element's buf is either allocated or NULL".

  • The rule 109618 broke: "whenever request memory becomes reachable (to cleanup code), its contents are fully initialized"
  • The rule 109619 broke: "when a request ends, every global that points into that request's memory has been reset"

For 109618 the GHSA says request memory is temporarily reachable before it is fully initialized; if an allocation fails then, the early exit is not accounted for and invalid state is left behind.

Reading the patch: what changed and how

The PHP fix is in the php-src commit 506e87fa7dcd "Avoid state corruption via bailout" (18 October 2026, PHP-8.4 branch). Its message has two lines:

  • Replace bailout on OOM with UnwindExit
  • Properly reset various globals that may be accessed during startup

On the PHP-8.4 branch the commit changes over 300 files (GitHub's comparison view caps at 300, so the author did not confirm the exact count). The parts the author actually read are the diff statistics, the allocator core (Zend/zend_alloc.c) and the session extension (ext/session/session.c). Most of the change is tests that deliberately trigger out-of-memory.

Fix 1: do not longjmp on out-of-memory (Zend/zend_alloc.c)

Before the fix, exceeding the memory limit called zend_mm_safe_error(), which raised an error and called zend_bailout() (an exit via longjmp).

After the fix:

SituationBeforeAfter
Normal limit (memory_limit) exceededlongjmp out immediatelyDelayed OOM: record "pending", set the VM interrupt flag and carry on
Next safe point (VM interrupt check)—zend_handle_delayed_oom() leaves through a proper unwinding exception (UnwindExit)
A second, higher (hard) limit exceeded—Prints "Hard memory limit of … bytes exhausted" to stderr and kills the process with _exit(137)

The point is that "jump right here" became "record it, and stop at a safe point". If memory use runs away past the hard limit, the process ends with no cleanup at all — a deliberately blunt last resort to keep broken state from being read by anyone.

A new setting, memory_hard_limit_percent, was added as well. As far as the author read, the default is unset (-1), in which case the limit is about 200% of memory_limit, or memory_limit + 1 GB when memory_limit exceeds 1 GB. Values below 100 (other than -1) are rejected with a warning.

Operational impact (author's reading): on reaching the hard limit PHP does not show a normal error page — the process exits immediately (status 137). With FPM a child dies and the master restarts it; with mod_php an Apache child dies. After updating, add monitoring for "Hard memory limit" in logs and for an increase in abnormal worker exits.

Fix 2: always reset request-owned state (ext/session/session.c and others)

In the session extension's diff you can see:

  • PS(in_rfc1867_update) = false; added to per-request initialization (php_rinit_session_globals)
  • A stale TODO removed: "These should be initialized by php_rshutdown_session_globals() always when execution is finished"
  • The upload-progress handler (which runs during request startup, before normal initialization) now keeps objects as incomplete classes, so no user code can run

So what was fixed is that even if cleanup is skipped, the next request's initialization does not trust stale state. The commit message's "Properly reset various globals that may be accessed during startup" refers to this.

The invariants the fix protects

#InvariantMechanism
1Do not leave partway through initializationReplace longjmp with delayed OOM and unwinding at a safe point
2If memory use runs away, stop without letting anyone read broken stateHard limit and _exit(137)
3Do not keep references to old memory across requestsReset every global at request start and end
4Work that runs before initialization must not touch untrusted stateLimit work during startup and run no user code

Why happy-path tests are not enough

Bugs like this live in code that runs only on error paths (out of memory, fatal errors). Ordinary tests assume memory is available, so they never reach these paths.

The commit adds a large number of out-of-memory tests, such as Zend/tests/oom_*.phpt. A code comment explains that ZEND_MM_MAX_ALLOCS fails the n-th allocation of a request, so the OOM handling can be exercised at any allocation, not only at allocations big enough to hit the limit.

This idea carries over to ordinary applications: a test that fails the n-th call (fault injection) exercises error paths that are normally never run.

A safe teaching example: watching memory lifetimes with AddressSanitizer

Here is the same class of bug in small C programs. To repeat: it is not PHP code and not a reproduction of PHP2Shell. It just lines up three ingredients — per-request memory, a global reference to it, and longjmp — in simplified form. Run it in an isolated environment of your own.

Example 1: a global reference outlives the freed region (the 109619 class)

/* Teaching code: per-request memory and a global pointer into it */
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static jmp_buf bailout;
static char *arena;        /* per-request memory */
static char *cached_name;  /* a global that outlives the request */

static void *req_alloc(size_t n, size_t limit) {
  if (n > limit) longjmp(bailout, 1);   /* "memory limit exceeded": jump out */
  return arena;
}

static void handle(const char *input, size_t limit) {
  cached_name = req_alloc(16, limit);
  strcpy(cached_name, "session-A");
  req_alloc(strlen(input) * 1000, limit);   /* may jump out here */
  cached_name = NULL;                       /* runs only on success */
}

static void request(const char *input, size_t limit) {
  arena = malloc(64);
#ifdef FIXED
  if (setjmp(bailout) == 0) handle(input, limit);
  cached_name = NULL;                       /* fix: reset at the boundary, on every path */
#else
  if (setjmp(bailout) == 0) handle(input, limit);
#endif
  free(arena);                              /* request end: release the region */
}

int main(void) {
  request("x", 1u << 20);                   /* a normal request */
  request("a-very-long-input", 64);         /* failure path: jumps out midway */
  if (cached_name) printf("next sees: %s\n", cached_name);   /* reads freed memory */
  else puts("next sees: (cleared)");
  return 0;
}
clang -g -O0 -fsanitize=address lifetime.c -o bug
clang -g -O0 -fsanitize=address -DFIXED lifetime.c -o fixed
./bug     # aborts, reporting a read of freed memory
./fixed   # exits normally

Result of the author's run (Apple clang 21.0.0, -fsanitize=address):

  • Before the fix: AddressSanitizer: heap-use-after-free, with stack traces for where it was freed (free(arena) in request) and where it was allocated
  • After the fix (-DFIXED): prints next sees: (cleared) and exits with nothing detected

What to take from it:

  • The cause is that the reset exists only on the success path — cached_name = NULL; is not run once longjmp jumps out
  • The fix is to reset at a boundary every path goes through (this mirrors PHP's fix 3)

Example 2: jumping out mid-initialization, then cleanup reads broken state (the 109618 class)

/* Teaching code: add to a list, then jump out before initializing the contents */
struct node { struct node *next; char *buf; };
static struct node *head;      /* the list walked at request end */

static void add_header(size_t len) {
  struct node *n = malloc(sizeof *n);    /* contents uninitialized */
  n->next = head; head = n;              /* published to the list too early */
  n->buf = req_alloc(len);               /* may jump out here */
}

static void shutdown_request(void) {     /* always runs */
  for (struct node *n = head, *next; n; n = next) {
    next = n->next;
    free(n->buf);                        /* trusts that buf is valid or NULL */
    free(n);
  }
}

Example 2 is an excerpt. req_alloc here is assumed to be a one-argument version of example 1's function, without the limit parameter. The -DFIXED variant and main are omitted, so this excerpt alone cannot reproduce the results below.

The fixed version (-DFIXED) records an allocation failure instead of jumping out on the spot, and handles it at the next safe point (the same idea as PHP's fix 1).

Result of the author's run:

  • Before the fix: ASan reports SEGV on unknown address (in shutdown_request, at the free(n->buf) line)
  • After the fix: prints "OOM handled at a safe point" and "shutdown completed", then exits normally

This shows another principle: finish initializing before you publish (for example, fill in the fields before putting the node on the list).

Limits of the teaching code

  • It is a conceptual model. It does not reproduce PHP's allocator (zend_mm) or the conditions an actual exploit needs
  • Behavior changes with optimization, OS and allocator (the ASan results are observations in the author's environment)
  • Making arbitrary code run is deliberately not reproduced here, and should not be

For operators: checking whether you are affected

Step 1: Identify the PHP your web server runs

php -v on the CLI and the PHP serving the web can differ (several versions side by side, containers, per-pool FPM versions).

# CLI version (may differ from the web)
php -v

# FPM version and running processes
php-fpm -v 2>/dev/null; ps aux | grep -E 'php-fpm|php-cgi|frankenphp|lsphp' | grep -v grep

# Is mod_php loaded into Apache?
apachectl -M 2>/dev/null | grep -i php

To know the version the web really runs, execute PHP on that server and print the version. Do it by an administrator-only means, and never publish a page that leaks version information.

Step 2: Check OS-vendor backports

On Debian, Ubuntu, RHEL and similar, a fix can be folded in without the version number rising. Don't conclude "unpatched" from the number alone.

# Debian/Ubuntu: does the changelog name the CVE?
apt changelog php8.3-fpm 2>/dev/null | grep -E 'CVE-2026-10961[89]'

# RHEL family
rpm -q --changelog php-fpm 2>/dev/null | grep -E 'CVE-2026-10961[89]'

If nothing turns up, check your distribution's official security tracker for whether your version is fixed.

Step 3: Look for end-of-life versions

  • PHP 8.1 and older are outside the PHP project's updates. Upgrade, or use a vendor LTS with backports
  • Given the severity, the PHP project provided minimal source backports for PHP 7.4, 8.0 and 8.1 (a stopgap if you build from source or have no LTS source)
  • Cisco Talos notes that PHP 8.2 security support ends on 31 December 2026. Use this as the occasion to plan a move to 8.3 or later

Step 4: Interim mitigations if you cannot update yet, and their limits

Updating comes first; the following only buys time. The vendor too says they reduce exposure to specific paths and do not make an installation safe.

GoalSettingCaveat
Reduce 109618 pathsmemory_limit=-1 (set where applications can't override it), a low post_max_size, size and field-count limits at the proxymemory_limit=-1 is not complete: if the underlying allocation fails, the vulnerable path remains. Do not use RLIMIT_AS or RLIMIT_DATA (they induce allocation failures). Also, memory_limit=-1 removes the per-request memory ceiling, so one request can exhaust the host's memory; pair it with a cgroup or container limit and treat it as temporary until you update
Close the confirmed 109619 pathsession.upload_progress.enabled=0 (php.ini, FPM pool or server config; restart all workers). Don't rely on ini_set() or .user.iniDoes not close other paths
109619 (PHP 8.5)fatal_error_backtraces=0, restart all workersOnly the one confirmed path
Reduce what is left of 109619Remove attacker-reachable fatal errors; pm.max_requests=1 if you can give up performanceThe vendor states that no complete configuration mitigation exists
CVE-2026-115560session.upload_progress.enabled=0The same setting as the 109619 mitigation

Verify a setting against what the web workers actually read:

# CLI settings (may differ from the web workers)
php -i | grep -E 'session.upload_progress.enabled|memory_limit|fatal_error_backtraces'

# php.ini values FPM actually loads (closest to the web workers)
php-fpm -i | grep -E 'session.upload_progress.enabled|memory_limit|fatal_error_backtraces'

# Per-pool overrides (php_value / php_admin_value). php.ini values do not appear in -tt
php-fpm -tt 2>&1 | grep -E 'php_(admin_)?(value|flag)'

Step 5: Look for signs of compromise

JPCERT/CC, citing the discoverers, lists the following to check. No single detection rule is guaranteed to catch every attack.

  • Past HTTP responses that set a PHPSESSID cookie with an unnaturally long or malformed value
  • Suspicious multipart/form-data requests, and PHP memory-limit errors or HTTP 500s around them
  • PHP workers exiting unexpectedly or restarting frequently

The absence of a trace in logs is not proof of safety; the vendor likewise says log audits only cover the paths that were exercised.

In its 29 October update JPCERT/CC conveys reports that, in an investigation of attack activity, traces suggesting successful compromise of a specific version of a firewall product were found; that the attacker appears to have combined the PHP vulnerability with a Linux kernel privilege-escalation vulnerability; and that attempts at lateral movement into internal networks are suggested. Appliances and products that embed PHP, not only websites, are in scope.

For executives: what to decide, in what order

For non-engineers, the order of decisions:

  1. Today: list every server and service that runs PHP (ask staff or contractors). The less the IT department knows about something — an old admin screen, a contractor-built site, an appliance's embedded web UI — the more dangerous it is.
  2. This week: set update priorities. Start with what is internet-facing, on an old PHP version and handling customer data. Anything run via mod_php comes first.
  3. At the same time: get written confirmation of patch status from contractors and hosting providers. On shared hosting you depend on the provider.
  4. After: investigate for compromise together with the update. The update closes the hole, but an intruder who is already in stays in.
  5. Medium term: put the migration off PHP 8.1 and older, and off 8.2 as its support ends, in the budget.

"We only run WordPress, so we're fine" does not hold: if the PHP runtime is unpatched, you can be affected even when WordPress itself has no vulnerability.

Frameworks: Laravel and WordPress

PointPosition
Where the flaw isThe PHP runtime, not Laravel's or WordPress's code
ImpactAn app on that PHP can be affected regardless of any framework vulnerability
FixUpdate PHP to a fixed version. Updating the framework does not fix this
Separate matterFramework- or plugin-specific vulnerabilities are tracked separately

Because 109619 notes that fatal errors can be part of the path, fatal errors caused by plugins or extensions (for example in upload, import, error-page or shutdown handling) also matter, so reducing the fatal errors an attacker can reach remains a useful layer of defense after updating.

How CVE-2026-115560 relates

  • It is a separate vulnerability, disclosed by php.net on 23 October as an informational advisory
  • It applies only in an unusual combination: session.serialize_handler configured as php_binary or php_serialize, the app switching to php with ini_set() at run time and calling session_start(), with session upload progress enabled
  • php.net calls this setup unlikely in practice, will fix it in the regular release cycle, and promises a full advisory with the next release
  • When the author checked on 31 October 2026, no CVE record was public at cve.org or NVD (a "does not exist" response)
  • Whether this release (8.2.35 and the others) fixes it is not stated as "fixed" in the vendor's text. The vendor's interim mitigation is session.upload_progress.enabled=0

Do not treat the two PHP2Shell CVEs and 115560 as "the same vulnerability". Nor can you say they are "unrelated": both involve session upload progress. Until a new advisory appears, keep the configuration mitigation in place.

The author's view: what to learn from this

The following is the author's reading of the published facts.

  1. "Fix only once exploitability is proven" is a dangerous criterion. The researchers say an issue reported in 2020 and flagged in 2024 stayed unfixed until exploitation was shown. Corruption of state on error paths can look harmless alone and become severe in combination with other bugs.
  2. Happy-path tests do not find this kind of bug. What the fix added were tests that inject failure. In your own code, tests that "fail the n-th external call" or "fail a memory allocation" run the cleanup paths that normally never execute.
  3. The speed of updating decides the size of the damage. With exploitation observed, "wait and see" is not an option. Practising updates in peacetime determines the loss on days like this.
  4. PHP versions typically differ from server to server. Organizations without a complete asset inventory are the ones who miss things.

Conclusion and what to watch next

  • What can be said as fact: two separate CVEs were fixed in PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12. Both are on KEV and exploitation has been observed. The demonstrated RCE is mainly on mod_php, with conditional paths validated on FPM.
  • What cannot yet be said: whether attacks succeed on every runtime, and the real scale of damage. Whether a complete attack on 109618 is possible on FPM. The details of CVE-2026-115560.
  • To watch: the 115560 advisory and CVE, the next PHP release, distribution backport status, and updates from JPCERT/CC and IPA.

If you want a vulnerability assessment or code audit of your own service

The author assesses the security of web applications and cloud environments from production experience with Next.js, Python, Go and AWS. Updating PHP closes these holes, but problems left in the application itself — authorization flaws, misconfiguration, secret handling — need separate review.

What I can and cannot do, up front:

  • I can: perform source-and-configuration-based web application vulnerability assessments and code audits, with a prioritized fix plan and re-verification after fixes
  • I cannot: perform forensic investigation after a compromise, or discover vulnerabilities inside PHP itself. If you suspect compromise, contact a specialist incident-response firm first
  • I cannot promise you will be "completely secure". I report what was found and what was not examined, as it is

See the scope and pricing through the button below.

Frequently asked questions

What is PHP2Shell? Is it one CVE?
PHP2Shell is the name for two critical PHP vulnerabilities disclosed on 21 October 2026. CVE-2026-109618: out-of-memory handling corrupts partly initialized state, and request-shutdown cleanup then reads the broken state. CVE-2026-109619: state left by an earlier request keeps pointing at freed memory and is used before the next request is initialized. The mechanisms differ, so do not treat them as one vulnerability.
Which version should I update to?
PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12 or later. PHP 8.1 and older receive no updates from the PHP project, so you need to move to a supported version or rely on a vendor backport. Debian, Ubuntu, RHEL and similar can fix an issue without changing the version number, so check whether the package changelog mentions the CVE.
Is it being exploited?
Yes. CISA added both CVEs to the Known Exploited Vulnerabilities catalog on 26 October 2026. JPCERT/CC reports observed exploitation attempts and many public proof-of-concept claims, while noting that whether code can actually be executed depends on PHP version, environment and memory layout. Observations also describe much of the activity as scanning or simple attempts, so success and volume vary by environment.
Are there mitigations if I cannot update right away?
Yes, but they are incomplete. For 109618: memory_limit=-1 set where applications cannot override it, a low post_max_size, and size limits at the proxy. For 109619: session.upload_progress.enabled=0 set in php.ini, the FPM pool or server config (restart all workers), and on PHP 8.5, fatal_error_backtraces=0. Note that memory_limit=-1 removes the per-request ceiling, so pair it with a cgroup or container limit and treat it as temporary until you update. The vendor says updating is the only complete fix. Do not use RLIMIT_AS or RLIMIT_DATA, because they induce the vulnerable path.
Is CVE-2026-115560 the same as PHP2Shell?
It was disclosed as a separate vulnerability. Per php.net's 23 October informational advisory it needs session.serialize_handler configured as php_binary or php_serialize, the application then switching to php with ini_set() before session_start(), and session upload progress still enabled — an unusual combination. A full advisory is promised with the next release, and as of 31 October 2026 no CVE record is public. session.upload_progress.enabled=0 is the interim mitigation.
Are Laravel and WordPress affected?
The flaw is in the PHP runtime, not in the framework. If the PHP running Laravel, WordPress or Symfony is unpatched, it can be affected even if the application itself is free of vulnerabilities, which is the vendor's framing. Conversely, once PHP is on a fixed version, no framework change is needed. Framework- or plugin-specific vulnerabilities are a separate matter.

References

友田

友田 陽大

Developer of a METI Minister's Award–winning product. With TypeScript + Python + AWS, I deliver SaaS, industry DX, and production-grade generative AI (RAG) end to end — from requirements to infrastructure and operations — single-handedly.

Before you hold real customer data

Web app & SaaS security audit — authorization, tenant isolation and config, verified in the code

Beyond what tools catch, the design gap — who may touch which data — checked in the source code and configuration, with a prioritized fix plan. Not only Next.js / Supabase: web apps on Rails, Laravel, Django, Go and others, plus AWS / GCP / Vercel configuration. We never call anything “completely secure.”

Available for both project-based (contract) and advisory engagements. Start with a free 30-minute consult.

Also worth reading