PHP2Shell: Critical Pre-Auth RCE in the PHP Interpreter Itself

CVE-2026-109618 & CVE-2026-109619: what they are, who is actually exposed, and what “just patch it” really means.

TL;DR: On 21 October 2026, PHP shipped emergency releases fixing two critical vulnerabilities in the interpreter itself (CVSS v4.0 9.2 each; the 10.0 that circulated with the leak was never PHP’s rating). Both live in the machinery that processes multipart request bodies during request startup, before your application code runs, so the worst case is unauthenticated remote code execution as the web server user on any PHP page, with no application bug involved. Exploitation attempts were reported within twenty minutes of the release, at least one before it, and on 26 October a working chain was confirmed against a honeypot running mod_php on PHP 8.4. The bugs are real and weaponizable, but not turnkey: exploitation depends on the PHP build, the SAPI, and the effective configuration, and public tooling requires per-target preparation. Patch the runtime, recycle the workers, and verify the package that actually serves requests. Then do one more thing: unless you need it, turn session.upload_progress off and leave it off. A third, narrower issue in the same feature (CVE-2026-115560, published 23 October) is not fixed by the 21 October releases, and that setting is currently its only mitigation.

1. Background and timeline

PHP2Shell is the public name for two memory-safety vulnerabilities in PHP’s core, disclosed and fixed in an emergency release process:

  • CVE-2026-109618 (GHSA-w8hw-w9fx-j79w): “RCE via OOM corruption.” An out-of-memory bailout can interrupt the engine mid-operation and leave internal structures half-initialized; the request-shutdown path then reads or branches on that broken state.
  • CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp): “RCE via stale global state.” A long-lived worker process can retain global state that still references memory belonging to a previous request: a use-after-free at the interpreter level.

Both were rated critical, CVSS v4.0 9.2, with a vector (AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H) that encodes high attack complexity and attack requirements. That is the advisory’s compact way of saying what 4 spells out. PHP’s advisories credit the reports to researchers at Wiz, Calif and OpenAI’s Codex Security team; Wiz, which describes the discovery as AI-assisted, published the public technical analysis. PHP has also said that a core developer first saw signs of the out-of-memory problem during the project’s 2024 external audit, without finding a route to code execution at the time.

The release did not go to plan. On 20 October a post on Hacker News leaked both CVE identifiers and a disclosure date of 22 October. PHP published an advance notice that evening and brought the release forward to 21 October at 14:00 UTC. The same evening, according to the PHP Foundation, a video of a working proof of concept was posted by mistake. Cloudflare switched on firewall rules for all of its customers in the early hours of the 21st, the fixes shipped at 14:00 UTC, and watchTowr reported active exploitation attempts against both CVEs within twenty minutes. Amazon has since said its honeypots recorded an exploitation attempt on 17 October, four days before disclosure. On 26 October a honeypot run by Perplexity’s detection and response lead recorded the first publicly documented working chain, against Apache mod_php on PHP 8.4.26; Expel’s Marcus Hutchins called it the highest-quality confirmation of in-the-wild exploitation so far.

Stable branch First fixed release
PHP 8.5 8.5.12
PHP 8.4 8.4.27
PHP 8.3 8.3.36
PHP 8.2 8.2.35

Everything below those tags on each branch is affected, and the affected range reaches much further back than the table suggests. PHP 8.1, 8.0 and 7.4 are out of upstream support, but the vulnerable code is there too, and the PHP security team published minimal source backports for those three branches for people who build from source or are waiting on a vendor. Distribution packages for even older lines exist as well; Ubuntu shipped fixes back to PHP 5.5 under its extended support programs. Between the leak and the end of 21 October, roughly forty public repositories appeared under the vulnerability’s name (our count of repositories named for it, taken on 20 and 21 October), from defensive tooling and mirrors to weaponization attempts. If you operate PHP and have not patched since 21 October, treat the exposure window as open, and assume it opened before the 21st.

Two days later, on 23 October, PHP published an informational notice for a third, separate issue in the same feature, CVE-2026-115560. It is covered in 6.

2. What the bugs actually are

The headline attack surface, the one that needs no cooperation from the application, is the handling of multipart request bodies during PHP request startup. Before application code executes, PHP processes form fields and file uploads, potentially invoking session upload-progress handling. This makes certain attack paths application-independent: even a PHP page containing nothing but echo "OK"; can be exposed. Multipart parsing is the entry point, however, not the root cause. Nor is it the only entry point for the second bug: PHP’s advisory also names per-request INI diagnostics supplied by the frontend, the fatal-backtrace path on 8.5, and, on FPM, an application-stage session operation.

The underlying failures are in the Zend Engine’s memory and state management. PHP workers can handle multiple requests, allocating request-local memory and releasing it during shutdown. The engine represents values using zval structures and arrays using HashTable entries called Buckets. Meanwhile, some worker-global state survives between requests and may temporarily reference request-owned memory. Both vulnerabilities arise when interrupted operations break the assumptions that keep these structures valid.

The OOM-as-corruption bug (CVE-2026-109618). PHP handles fatal out-of-memory (OOM) failures through zend_bailout(), abandoning the current operation without normal cleanup. In _zend_hash_str_add_or_update_i(), the HashTable counters (nNumUsed and nNumOfElements) are incremented before zend_string_init() finishes allocating the new Bucket’s key. If that allocation fails, the Bucket remains partially initialized. During shutdown, zend_hash_destroy() uses nNumUsed to traverse the table and may call pDestructor() on the uninitialized zval, turning an OOM condition into memory corruption. This bug does not depend on session upload progress.

The stale-state bug (CVE-2026-109619). A different failure occurs when worker-global state outlives the request memory it references. PHP’s PS(...) macro accesses session globals, including PS(id), a zend_string * holding the session ID, and PS(http_session_vars), a zval normally referencing the $_SESSION array. A zend_string stores its length in len and its contents in a variable-sized val[] buffer. During early upload-progress handling, these globals can reference request-owned allocations. If an interrupted operation prevents their cleanup, a later request on the same worker may access or destroy already-freed memory, producing a cross-request use-after-free (UAF). In some exploit chains, reinterpreting freed memory as a zend_string can also corrupt its apparent length, enabling an out-of-bounds read.

A third ingredient makes these bugs easier to reach: multipart processing can allocate substantially more memory than the HTTP body suggests. Excessive part headers, nested field names and empty-file metadata can amplify memory consumption until a request exhausts PHP’s memory limit. That provides a trigger, not automatic code execution. Turning either vulnerability into RCE requires additional control over memory layout and, in many public exploit chains, a way to defeat ASLR. Those constraints are examined in 4.

3. Impact: who is actually at risk

Not every PHP installation is exposed the same way. Three factors decide: the SAPI, the build, and the configuration.

Apache with mod_php (prefork) is the primary surface. mod_php runs request shutdown even when startup has failed, so for the out-of-memory bug the triggering request itself processes the broken state, and the worker survives to serve again. For the stale-state bug that survival is what matters: the next request on the same worker consumes what the failed one left behind. We verified full pre-auth RCE in our labs on this deployment shape: as the www-data user, against a target page containing nothing but echo, on multiple 8.4/8.5 builds. Both chains were verified on both x86-64 and ARM64. This includes stock production configuration (errors hidden, default memory limit) and the stock worker pool: single-worker labs for the repeatable measurements, and the default 150-worker pool solved by holding the other children with slow uploads. PHP’s own advisory says the same thing in its own words: unauthenticated RCE as the web worker account was “validated over HTTP with default PHP input and memory limits and normal prefork configurations with multiple workers.”

PHP-FPM is different, not safe. If the failure happens during request startup, the FPM child terminates and the cross-request state never gets consumed: a crash, not a compromise. For the out-of-memory bug, PHP says source analysis suggests FPM is susceptible but that no complete FPM exploit has been demonstrated. For the stale-state bug the advisory is explicit: “Session lifecycle RCE was validated against mod_php and FPM”, with a normal dynamic pool, provided the application performs a suitable operation after startup. FPM pools that recycle aggressively are safer by accident, not by design; the advisory even lists pm.max_requests=1 as a mitigation for those who can afford it.

Other SAPIs are in scope and under-tested. PHP’s source analysis rates FrankenPHP as likely susceptible to the application-independent chain in the same way as mod_php. LiteSpeed’s LSAPI is modeled on FPM, and PHP calls application-specific exploits against it likely but unvalidated. php-cgi is on PHP’s affected list but is not discussed in either advisory. We did not test any of these three.

CLI and single-request SAPIs are not a network exposure for the cross-request family, though they do not prove absence of the corruption-during-shutdown class.

Two consequences deserve emphasis because they invert usual expectations:

  • Application patching does not apply. No plugin audit, no CMS update, no “we don’t have file uploads” argument reduces this risk, because the bug is below the application. What can reduce exposure is refusing the triggering input before it reaches PHP, which is why PHP’s own guidance includes frontend limits on multipart (6).
  • Code execution as the web server user is the start of the impact, not the end. In typical LAMP deployments that user reads application secrets, database credentials, and source code; it is the standard pivot to full host compromise.

What a successful attack looks like from outside: a handful of crafted POST requests to an ordinary page, interleaved with normal traffic. Nothing appears in application-level logs, because nothing reaches the application. The web server’s access log does record the POSTs, which is where 5 starts.

4. Real-world exploitation requirements: the deep dive

Is the internet on fire? Not automatically, and not yet at the scale the severity rating might suggest, but the window is open. Exploitation attempts were reported within twenty minutes of the release, and Cloudflare says it is seeing attack traffic against customers and attackers changing payloads to evade its rules. On 26 October a working chain was confirmed against a honeypot (mod_php, PHP 8.4.26), with the leaked data arriving as an oversized session cookie, which is exactly the kind of artifact 5 lists. What is still not public, at the time of writing, is confirmed mass compromise. The gap between those two facts is the subject of this section. We spent the disclosure week reproducing the public claims end-to-end in our labs, where we extended the public tooling to stock production configuration and verified the full chain ourselves, and the practical constraints are real. Here is what an attacker actually needs, at the level of detail useful for risk assessment.

4.1 Not a drive-by: per-build calibration

The corruption gives an attacker tenuous control: a stale reference, a forged pointer. Turning that into code execution requires knowing, with byte precision, where things land in the target’s memory: function addresses in the PHP library and the exact heap geometry of the target build. Those values differ per PHP version, per distribution build, per architecture, and even per configuration of the target.

ASLR and information disclosure. Address Space Layout Randomization (ASLR) randomizes the base addresses of libraries and memory regions between process executions. Even when an attacker knows the offset of a function inside libphp, its runtime address remains unknown. The relationship is straightforward: runtime address = module base + symbol offset. Public exploit chains therefore often require an information-leak primitive to recover the randomized base address before using known offsets.

Offsets and exploit profiles. Function offsets, such as those of zif_system and zval_ptr_dtor, can typically be extracted statically from the exact PHP binary. Other profile entries may represent global-state locations, heap-relative positions or parameters controlling individual exploitation stages. These are not interchangeable, and not everything called an offset is actually one. Their values can differ across PHP versions, distribution builds, architectures and compilation options.

Heap grooming. Knowing the addresses is only half the problem. Heap grooming manipulates the allocator’s state through controlled allocation and deallocation patterns, increasing the likelihood that a new object occupies a previously freed memory region. This matters particularly for use-after-free exploitation, where a stale pointer may then reference a different object. PHP’s Zend Memory Manager organizes allocations into size classes and reuses memory blocks, making object size, allocation order and worker state important. Unlike symbol offsets, grooming parameters cannot simply be extracted from libphp. Public PoCs commonly hardcode previously calibrated allocation sizes, object counts and memory-layout assumptions for a known environment. These parameters are determined experimentally and may need recalibration when the PHP build, SAPI, allocator behavior or configuration changes. The exploit can then use runtime information disclosure to resolve ASLR-randomized addresses while relying on those pre-established heap-layout assumptions.

This explains why public tooling carries per-build profiles and why an unprofiled target may require additional calibration. It is a meaningful speed bump for mass exploitation, but not a wall. The work only has to be done once per sufficiently similar deployment profile, and calibrated profiles can be shared.

4.2 Configuration reality check

We tested the usual “we’re hardened” assumptions against the full chain in our labs. The results, in brief:

Configuration Does it stop the chain?
display_errors = Off (production default) No. The modern chain was built against exactly this posture.
memory_limit at production values No. Amplification defeats it as a size cap; it only changes the arming arithmetic.
expose_php = Off No. It removes a fingerprint and slightly shifts memory layout; the chain adapts.
session.upload_progress.enabled = Off Mostly, for these entry paths. It removes the parser hook that arms the session-state chains, an effective interim measure, but it does not repair the underlying bug class or the OOM handling. Patch anyway.

PHP’s advisory for the stale-state bug adds a point we did not need a lab to confirm: changing error_reporting, suppressing with @, or disabling display_errors or log_errors does not protect against it. The diagnostics are a consumer path whether or not you can see them. The takeaway matches PHP’s own wording: “There is no complete generic configuration mitigation.” If your plan is “we’re configured safely,” your plan is patching.

4.3 The distro nuance most coverage missed

“PHP 8.3.6 is less than 8.3.36, therefore vulnerable” is wrong more often than not, and the opposite mistake is just as easy to make. Distributions handled this in two different ways.

Ubuntu backported under its own revision scheme. On 24.04 the fixed package is php8.3 8.3.6-0ubuntu0.24.04.13 (USN-8948-1, 21 October), and the version string reads 8.3.6 before and after the fix. The same notice covers 22.04 (php8.1 8.1.2-1ubuntu2.28), 26.04 and 26.10, and USN-8948-2 extends the fix under Ubuntu Pro to 20.04’s php7.4 and older lines back to 14.04. Debian instead moved to the fixed upstream releases: php8.2 8.2.35-1~deb12u1 on bookworm (DLA-4848-1) and php8.4 8.4.27-1~deb13u1 on trixie (DSA-6574-1). On Debian, the upstream number therefore does tell you something; on Ubuntu it tells you nothing.

We verified Ubuntu’s fix behaviorally. The patched 24.04 package (php8.3 8.3.6-0ubuntu0.24.04.13, the USN-8948-1 revision) retains nothing when pushed to four million multipart headers, roughly a gigabyte of represented data. Version strings overstate exposure; the package revision is what matters.

That cuts both ways. Real-world exposure concentrates in two places: source-built and container-image deployments (which do not update in place; a running container keeps the old interpreter until the image is rebuilt or updated from a fixed package or tag), and distribution installs lagging security updates. A box that has not run apt upgrade since 21 October is exactly as vulnerable as its version string says. Check the package’s security advisory status against the CVE list, not the version string. And after updating, recycle the workers: a long-lived mod_php child or FPM worker keeps executing the old binary until it is restarted. Canonical’s own guidance says the same, and notes that unattended-upgrades installs the package but does not restart Apache for you.

4.4 What still separates an attacker from RCE

Three things, in practice:

  • The leak has to land first. Every public chain we have seen defeats ASLR with an information-leak stage that must succeed before the corruption stage can be aimed, and the chain confirmed in the wild on 26 October did the same. It is not a law of nature, but it is where unprofiled or unusual builds fail today.
  • The final stage is probabilistic. Even calibrated, the decisive heap manipulation does not fire every attempt; public tooling retries, which produces recognizable traffic patterns (see 5).
  • Older lines resist the public approach. On the 8.2-and-older branches we tested, the memory layout after the OOM differs enough that the public leak techniques do not transfer; against those installations the public chains we tested stop at a crash. PHP 8.3 was measured separately and sits on the same side of the line: the older RFC1867 parser OOMs in the input-filter and session-decode paths before the dangling-session-id site that the leak consumes, so the public leak stage does not transfer there either, and the patched 8.3.36 build showed no retention under the same probes that leave unpatched builds retaining memory. Treat that as a research frontier, not a safety guarantee.

4.5 The skill and noise profile

Pulling this together: successful exploitation requires memory-exploitation competence, target-specific preparation, and visible side effects on the wire and in logs. The requests are large and structurally abnormal (far more multipart parts than any real upload form), they repeat in short windows when a stage retries, and they leave distinctive traces in the engine’s error output. Mass-scanning for vulnerable PHP is cheap; turning the primitive into code execution on any given target is not. That asymmetry is your detection opportunity.

5. Detection guidance

None of these signals is specific on its own; the value is in the combination and in the ordering (anomalous request, then engine-level distress, then post-exploitation artifacts).

On the wire:

  • Multipart POSTs with an abnormal number of parts or part headers, including runs of empty file parts, especially to endpoints that do not accept file uploads.
  • Multipart POSTs that carry a PHP_SESSION_UPLOAD_PROGRESS field, or a session cookie, to pages that have no upload form.
  • POSTs using chunked transfer encoding (no Content-Length) to ordinary pages, or multipart bodies whose declared size is inconsistent with the connection’s behavior.
  • Bursts of near-identical large POSTs in a short window: the retry signature of a probabilistic final stage.
  • Session cookie responses with implausible sizes or content.

The bullets say POST because that is what the public chains use. PHP 8.4 and later can parse a multipart body on other methods as well, so key rules on the body shape, not the method.

On the host:

  • PHP fatal errors about memory exhaustion attributed to startup frames (e.g. in Unknown on line 0) rather than application code. This is the single most characteristic artifact.
  • Worker recycles or child terminations not explained by ordinary load.

PHP’s own advice for the log side is worth following to the letter: audit in an isolated environment with log_errors=On, a working error_log and error_reporting=E_ALL, and remember that a clean log is not proof of safety.

After the fact: correlate by time and worker process. Files appearing in web roots owned by the server user, outbound connections, and credential-file reads following the events above are your post-exploitation hunt.

A WAF can blunt the surface while you patch. Cloudflare enabled rules for all plans before the patch shipped and has already reported attackers varying payloads to get around them; the same caveat applies to every ruleset, commercial or not. Coverage also depends on your requests actually traversing it, and the framing can look ordinary to rules tuned for application-layer attacks.

6. Why patching is the fix, and the one setting to change as well

The emergency releases did not just bump a version. For the out-of-memory bug, the patch removes the long jump on allocation failure entirely: out-of-memory now produces a delayed “soft” condition handled at the next safe point in the VM, with an immediate hard exit if memory use reaches a second, higher threshold, so shutdown never runs against half-built state. For the stale-state bug, the patch resets a much wider set of request-owned state between requests, including error, session, object and extension state. The fix is deep, and no subset of it reproduces the whole guarantee.

Interim measures, scoped the way PHP scopes them:

  • session.upload_progress.enabled = 0, then restart every worker. Effective against the session-state entry paths, and cheap if you don’t use the feature. It must be set in startup configuration; changing it at runtime is too late. PHP suggests keeping it off after patching if you don’t need the feature, and since 23 October there is a second reason to (below). Not a fix for the class.
  • memory_limit = -1, set with php_admin_value so no pool, directory or application setting can restore a finite limit, then restart every worker. PHP’s own interim guidance for the OOM trigger, and PHP calls it incomplete: if an underlying mmap() fails, the vulnerable path still runs. That is also why RLIMIT_AS and RLIMIT_DATA are the wrong tool here; they make mmap() fail, which is precisely the condition the bug needs. Container or cgroup memory limits are PHP’s suggested alternative, with the same “not guaranteed” caveat and real availability risk.
  • Constrain the shape of input. Keep post_max_size conservative, enforce decoded request size at the frontend, cap multipart parts, headers per part, uploads and input variables, and lower max_input_nesting_level. If the application does not use multipart form data at all, block it at the frontend, for every method rather than POST alone.
  • On PHP 8.5 only, fatal_error_backtraces = 0, then restart. This closes the confirmed fatal-backtrace path and nothing else.
  • Remove diagnostics from per-request configuration. Invalid or deprecated directives in .htaccess php_value lines and in PHP_VALUE or PHP_ADMIN_VALUE passed from the frontend are a consumer path for the stale-state bug; PHP notes that FPM pool values and .user.ini do not provide the same early consumer. Move configuration to php.ini, the FPM pool or the server config, and delete obsolete directives wherever they live.
  • Fix attacker-reachable fatal errors, and treat execution timeouts as fatal errors. Upload, import, error-page, shutdown, destructor, serialization and output-handler paths are the ones PHP names.
  • On FPM, pm.max_requests = 1 if you can afford the cost. It closes the cross-request family on FPM and does nothing for mod_php.

Updating your CMS is irrelevant; the interpreter is the vulnerable component. Update the runtime that actually serves requests (not the CLI binary, not the container image tag) and restart every worker pool afterward.

The third issue. On 23 October PHP published an informational notice for CVE-2026-115560, a separate bug in session upload progress that the 21 October releases do not fix. The conditions are narrow: upload progress enabled, session.serialize_handler set to php_binary or php_serialize in the server configuration, and an application that switches it to php at runtime with ini_set() before session_start(). PHP describes it as an unlikely RCE vector, is handling it in the next regular bugfix release rather than an emergency one, and will publish the full advisory then; no exploitation has been reported. Its only current mitigation is session.upload_progress.enabled = 0. The conditions are also the exit: an application that never switches serializer at runtime does not meet them, so if you need upload progress and can confirm your code does not do that, keeping the feature on is a defensible choice. If you turned the feature off last week, leave it off. If you turned it back on after patching, turn it off again unless you need it.

One post-patch note that follows from the new design: because the soft limit is now enforced at the next safe point and the hard limit sits above it, a request can transiently exceed the old memory_limit before aborting. If you run PHP with tight memory ceilings in containers, validate pool sizing after upgrading.

7. Recommendations checklist

  1. Inventory by package, not by version string. For every internet-facing PHP service: which runtime build, which distribution package revision, which SAPI.
  2. Patch to a fixed release or a distribution package carrying the backport. Verify the advisory status of the exact package (USN-8948-1/-2 on Ubuntu, DSA-6574-1 and DLA-4848-1 on Debian, the GHSA advisories for everything else).
  3. Restart every worker (Apache children, FPM pools) after patching, then verify that the running processes were actually restarted: compare worker start times with the package install time. Whether the package manager restarts anything is deployment-specific, and unattended-upgrades does not restart Apache for you.
  4. Turn session.upload_progress.enabled off where the feature is not needed, and keep it off after patching: PHP recommends that for CVE-2026-109619, and it is the only current mitigation for CVE-2026-115560.
  5. Monitor the signals in 5, starting now. The vulnerability window you should assume runs from your last unpatched day, exploitation attempts predate the 21 October release, and a working chain has been confirmed in the wild since the 26th.
  6. Watch for the next PHP bugfix release, which will carry the CVE-2026-115560 fix and its full advisory, and re-evaluate step 4 then.
  7. If compromise is suspected: preserve evidence before remediation wipes it, then rotate application and database credentials reachable by the web server user.

8. FAQ

Is my WordPress/Drupal/MediaWiki site more exposed than a bare PHP page? No. For this bug family, the application is irrelevant; the chain runs before it. (Some related chains in the same feature do abuse application behaviors like a plugin’s local-file inclusion or a per-directory configuration mistake, but the interpreter-level chain needs none of that.)

Does my CDN or WAF protect me? Partially at best. The trigger is ordinary-looking HTTP framing; rulesets exist, Cloudflare’s are on by default, and attackers were already varying payloads to evade them within the first day. Coverage depends on your traffic path. Do not count it as a fix.

Are the public exploits turnkey? No. They are per-build-calibrated research tools. That said, “my build is unusual” is a delay, not a defense; profiles get built and shared.

Is PHP-FPM safe? No. The startup-phase failure kills the child (a crash), but failures after startup leave stale state in a surviving worker, and PHP’s advisory states that session lifecycle RCE “was validated against mod_php and FPM.”

I patched on 21 October. Am I done? Almost. Restart the workers if you have not, and turn session.upload_progress off unless you need it: CVE-2026-115560, published 23 October, is not fixed by those releases and that setting is its only current mitigation. The conditions for it are narrow (6), but the setting costs nothing if you don’t use the feature.

We run ARM64. Are we safe? No. We verified the full 8.4 and 8.5 chains on native ARM64 in our labs, including against production configuration.

We’re on PHP 8.3 or earlier. Do we care? Yes, but differently: the OOM trigger and the crash primitive apply, while the public leak-based chains we tested do not currently transfer. That’s a research gap, not a safety property. Patch, using the vendor package or PHP’s source backports for 7.4, 8.0 and 8.1.

Was this really found by AI? Wiz says its discovery was AI-assisted, and PHP credits the reports to researchers at Wiz, Calif and OpenAI’s Codex Security team. PHP has also said a core developer saw signs of the out-of-memory issue during the 2024 external audit without finding a path to code execution. Both things can be true; the exploitation chain, not the crash, is what was new.

9. How we verified this

Everything above marked as verified comes from our own instrumented labs: isolated containers per target build (official images and distribution packages), stock and hardened configurations, both x86-64 and ARM64, with full-chain proofs executed end-to-end as the unprivileged web server user, plus allocator-level instrumentation. We also verified the fix’s effect behaviorally: patched distribution builds show no memory retention even at the extreme request scales the attack requires. Where we quote PHP’s advisories, the wording is theirs. Claims we could not verify independently are attributed to their sources below or left out.

10. Sources

Author Author by Bruno Morisson and Ricardo Santos


© 2026 INTEGRITY S.A. All rights reserved.