Using AWS WAF to apply mitigations for PHP2Shell RCE vulnerabilities (CVE-2026-109618 and CVE-2026-109619)

Post Syndicated from Alex Waddell original https://aws.amazon.com/blogs/security/using-aws-waf-to-apply-mitigations-for-php2shell-rce-vulnerabilities-cve-2026-109618-and-cve-2026-109619/

On October 21, 2026, the PHP project released emergency fixes for two critical remote code execution (RCE) vulnerabilities in the PHP core runtime, tracked as CVE-2026-109618 and CVE-2026-109619 and collectively named PHP2Shell. Both are rated 9.2 (Critical) under CVSS v4.0, and both allow an unauthenticated attacker to run code on a vulnerable server. The fixed releases are PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35.

Patching is the only complete fix, and you should upgrade PHP as your first priority. But patching a fleet takes time: you need to inventory where PHP runs, schedule maintenance windows and test applications against the new builds. This post shows you how to use AWS Web Application Firewall (AWS WAF) to help reduce exposure to the confirmed attack paths during that window. You’ll learn which request patterns to block, how to write the rules in AWS WAFv2, how to deploy them without breaking legitimate traffic and where its protection ends, so you don’t develop a false sense of safety. For how Amazon threat intelligence detected PHP2Shell exploitation before public disclosure, see Amazon Threat Intelligence identifies PHP2Shell exploitation prior to public disclosure in MadPot. For AWS service status and the AWS WAF rule that AWS recommends, see AWS Security Bulletin 2026-143-AWS.

IMPORTANT: Patching is the only complete fix, and you should upgrade PHP as your first priority.


The vulnerabilities in brief

Both PHP2Shell vulnerabilities are unauthenticated RCE issues rooted in how PHP handles multipart/form-data request processing (the request format browsers use for file uploads) before your application code runs, which is why the AWS WAF rules in this post focus on multipart traffic, request body size, and the session upload progress field. At a high level, CVE-2026-109618 corrupts memory when PHP runs out of memory mid-request, and CVE-2026-109619 lets one request leave behind stale data that a later request on the same worker process reuses. For the root-cause analysis, affected versions, and PHP’s own guidance, see the official PHP advisories and release announcement:

Where AWS WAF fits in your response

AWS WAF is a defense-in-depth control in this situation, not a replacement for the PHP upgrade. The PHP advisories are explicit: updating to a patched release is the only complete mitigation. One of the two vulnerabilities is largely outside the reach of any web application firewall, as explained later. Treat the rules in this post as mitigating controls that help reduce exposure while you patch, then remove them or keep them as supporting controls after you’ve patched.

AWS WAF inspects HTTP requests at the edge. It doesn’t parse the internal structure of a multipart body, and it has no visibility into PHP worker memory or server-side configuration. The following table maps each attack element to whether AWS WAF can help mitigate it.

Attack element

AWS WAF coverage

Session upload progress field in a multipart POST (PHP_SESSION_UPLOAD_PROGRESS, the form field that turns on PHP’s upload-tracking feature)

Yes. A targeted rule can block requests carrying that field.

Multipart upload path (multipart/form-data, the request type used for file uploads and the entry point for both vulnerabilities)

Yes, if the application has no legitimate multipart uploads. Block multipart/form-data.

Out-of-memory condition from an oversized body

Partial. Cap the request body size. Doesn’t catch header amplification (many small part headers that cost far more memory to represent than their size on the wire) that stays under the cap.

Repeated attempts against the same worker (the reused PHP process that handles many requests)

Yes. A rate-based rule blunts the volume an exploit needs.

fatal_error_backtraces producer (a PHP 8.5 setting that stores crash-trace state across a request)

No. This is a server configuration setting (fatal_error_backtraces=0).

Invalid or deprecated INI diagnostics as a consumer (warnings PHP raises when applying bad configuration settings)

No. This path runs server-side, not over client HTTP.

Where an application does not accept multipart uploads, an edge rule that blocks multipart/form-data removes the multipart out-of-memory path that works against any application, plus the session-upload-progress trigger, which is a defense-in-depth control during the patch window.

If your application does use multipart uploads, AWS WAF reduces risk but does not close the vulnerability, because header amplification (a few kilobytes of part headers that expand into far more memory inside PHP) stays within size limits and the firewall cannot parse the headers inside individual body parts. In that case, prioritize the PHP upgrade and apply the server-side mitigations described later.

Implementing the AWS WAF rules

The rules below are AWS WAFv2 JSON, deploy each of them on the WAF protection pack (web ACL) associated with the Amazon CloudFront distribution, Application Load Balancer, or Amazon API Gateway stage in front of your PHP workloads.

IMPORTANT: Before implementing any changes, ensure that your WAFv2 logging is setup in line with AWS WAF Logging guidance. Start every rule in Count mode, confirm it does not match legitimate traffic, then switch to Block.


Request body inspection limits

AWS WAF inspects a bounded portion of the request body. On Application Load Balancer and AWS AppSync the limit is a fixed 8 KB. For AWS services such as CloudFront and API Gateway, the default is 16 KB and you can raise it to 32, 48, or 64 KB through the web ACL AssociationConfig as seen below. Any part of the body beyond the inspection limit counts as oversize. Choose the limit that fits the rules you deploy, because a body-size rule can only enforce a cap up to the inspected size.

aws wafv2 update-web-acl ... --association-config \
'RequestBody={CLOUDFRONT={DefaultSizeInspectionLimit=KB_16}}'

AWS WAF Rule

This rule targets both CVEs by blocking a request only when all three conditions in its AndStatement are true at once:

  1. The method is exactly POST – matched on the HTTP method, no transformation.
  2. A PHP session identifier is present (the nested OrStatement, so either sub-condition satisfies this leg):

    • PHPSESSID appears as a cookie key (exact match on the key, scanning all cookies), or
    • PHPSESSID appears anywhere in the request body (contains match).
  3. The body contains PHP_SESSION_UPLOAD_PROGRESS – the form field that activates PHP’s session upload progress feature.

Pair the rule with session.upload_progress.enabled=0 on the server, which turns the feature off.

{
  "Name": "PHP2Shell",
  "Priority": 0,
  "Statement": {
    "AndStatement": {
      "Statements": [
        {
          "ByteMatchStatement": {
            "SearchString": "POST",
            "FieldToMatch": {
              "Method": {}
            },
            "TextTransformations": [
              {
                "Priority": 0,
                "Type": "NONE"
              }
            ],
            "PositionalConstraint": "EXACTLY"
          }
        },
        {
          "OrStatement": {
            "Statements": [
              {
                "ByteMatchStatement": {
                  "SearchString": "PHPSESSID",
                  "FieldToMatch": {
                    "Cookies": {
                      "MatchPattern": {
                        "All": {}
                      },
                      "MatchScope": "KEY",
                      "OversizeHandling": "CONTINUE"
                    }
                  },
                  "TextTransformations": [
                    {
                      "Priority": 0,
                      "Type": "NONE"
                    }
                  ],
                  "PositionalConstraint": "EXACTLY"
                }
              },
              {
                "ByteMatchStatement": {
                  "SearchString": "PHPSESSID",
                  "FieldToMatch": {
                    "Body": {
                      "OversizeHandling": "CONTINUE"
                    }
                  },
                  "TextTransformations": [
                    {
                      "Priority": 0,
                      "Type": "NONE"
                    }
                  ],
                  "PositionalConstraint": "CONTAINS"
                }
              }
            ]
          }
        },
        {
          "ByteMatchStatement": {
            "SearchString": "PHP_SESSION_UPLOAD_PROGRESS",
            "FieldToMatch": {
              "Body": {
                "OversizeHandling": "CONTINUE"
              }
            },
            "TextTransformations": [
              {
                "Priority": 0,
                "Type": "NONE"
              }
            ],
            "PositionalConstraint": "CONTAINS"
          }
        }
      ]
    }
  },
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "PHP2Shell"
  }
}

Additional WAF Rules to consider

Block multipart requests when the application has no uploads

NOTE: This rule, if implemented in Block mode, will break applications that require file uploads. If your application does not require file uploads, then blocking multipart/form-data removes the multipart out-of-memory path that works against any application for both CVEs at the edge.

A single named header is inspected in full, with no 8 KB header cap, so matching the Content-Type header is reliable.

{
  "Name": "Block-Multipart-FormData",
  "Priority": 1,
  "Action": { "Count": {} },
  "Statement": {
    "ByteMatchStatement": {
      "FieldToMatch": { "SingleHeader": { "Name": "content-type" } },
      "PositionalConstraint": "CONTAINS",
      "SearchString": "multipart/form-data",
      "TextTransformations": [ { "Priority": 0, "Type": "LOWERCASE" } ]
    }
  },
  "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "PHP2ShellBlockMultipart" }
}

Cap the request body size

Capping body size reduces the out-of-memory condition behind CVE-2026-109618 and the stale state it can leave behind. Use OversizeHandling: MATCH with a size constraint so that any body larger than the threshold is blocked, including bodies that exceed the inspection limit. To enforce a cap of N bytes, the web ACL body inspection limit must be at least N. Note that you can’t cap the numeric Content-Length with a size constraint, because the constraint measures the length of the header value string, not the number it contains. If your application has legitimate large uploads, scope this rule to non-upload paths with an AndStatement on the URI path, or it will break those uploads.

{
  "Name": "Block-Oversize-Body",
  "Priority": 3,
  "Action": { "Count": {} },
  "Statement": {
    "SizeConstraintStatement": {
      "FieldToMatch": { "Body": { "OversizeHandling": "MATCH" } },
      "ComparisonOperator": "GT",
      "Size": 8192,
      "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ]
    }
  },
  "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "PHP2ShellBlockOversizeBody" }
}

NOTE: if you already have the AWSManagedRulesCommonRuleSet managed rule group, the SizeRestrictions_BODY rule blocks bodies larger than 8 KB by default. If a specific managed rule breaks legitimate traffic, override that rule to Count rather than disabling the whole group.

Rate-limit repeated attempts

A rate-based rule on POST requests can reduce the volume an attacker can send, lowering the possibility that the vulnerabilities can be triggered by overloading the worker, while the stale-state path needs a producer request and a consumer request to land on the same worker. This rule complements a server setting of pm.max_requests=1, which recycles the worker on each request.

{
  "Name": "RateLimit-Posts",
  "Priority": 4,
  "Action": { "Count": {} },
  "Statement": {
    "RateBasedStatement": {
      "Limit": 100,
      "EvaluationWindowSec": 60,
      "AggregateKeyType": "IP",
      "ScopeDownStatement": {
        "ByteMatchStatement": {
          "FieldToMatch": { "Method": {} },
          "PositionalConstraint": "EXACTLY",
          "SearchString": "POST",
          "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ]
        }
      }
    }
  },
  "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "PHP2ShellRateLimitPosts" }
}

Server-side mitigations that complement AWS WAF

These host and runtime changes address the parts of CVE-2026-109619 that sit below the HTTP layer a WAF inspects, so they fall outside its scope by design. Apply them alongside the AWS WAF rules as the host and runtime layer of your defense.

  • Upgrade PHP to 8.5.12, 8.4.27, 8.3.36, or 8.2.35. This is the only complete fix. PHP 8.1 and earlier are no longer supported upstream, so check with your distribution or long-term support vendor for a backported fix, or plan a move to a supported branch.
  • Address CVE-2026-109618 at the PHP level. Set memory_limit=-1 so applications cannot override it, and keep post_max_size low (8M where the application accepts no uploads, 32M where it does). Enforce memory bounds through container or cgroup limits, never through RLIMIT_AS or RLIMIT_DATA, which trigger the vulnerable out-of-memory path.
  • Set fatal_error_backtraces=0 on PHP 8.5 and restart every worker. This disables the setting that stores crash-trace state across a request, one of the confirmed ways the vulnerability is triggered.
  • Set session.upload_progress.enabled=0 and restart every worker. This turns off the upload-tracking feature that’s the other confirmed trigger, and is prudent to keep off even after patching.
  • Prefer php.ini, FPM pool, or server startup configuration over per-request INI overrides (settings applied per request through .htaccess, php_value, or FastCGI PHP_VALUE). Remove obsolete directives so they don’t raise diagnostic warnings.
  • Eliminate fatal errors and execution timeouts on attacker-reachable routes, including upload, import, error-page, shutdown, serialization, and extension paths.
  • Set pm.max_requests=1 if performance allows, so each worker process is recycled after one request, which breaks the link between the request that plants stale data and a later request that would reuse it.
  • Turn on error logging (log_errors=On, a working error_log, error_reporting=E_ALL) and review your Apache, FPM, or proxy logs for repeated warnings, deprecations, fatal errors, and timeouts on attacker-controlled routes. The absence of errors is not proof of safety.

Getting started

Complete the following steps to get started:

  1. Inventory where PHP runs and which versions and server APIs (mod_php, FPM, FrankenPHP, LSAPI) are in use. Identify any public endpoint that accepts a request body.
  2. Decide whether each application uses multipart uploads. This determines whether you can deploy the WAF rule to block multipart requests.
  3. Create or update the web ACL in front of each PHP workload and add the applicable rules in Count mode. Raise the body inspection limit on CloudFront or API Gateway if a rule needs it.
  4. Watch the sampled requests and Amazon CloudWatch metrics for each rule. Confirm that legitimate uploads and large JSON POSTs aren’t matched.
  5. Switch the rules to Block after the metrics are clean. Order the priorities so the session upload progress and multipart rules run before the size and rate rules.
  6. Test with a benign multipart/form-data POST, an oversized body, and a request carrying PHP_SESSION_UPLOAD_PROGRESS. Expect a 403 response and the matching rule metric.
  7. In parallel, apply the PHP upgrade and the configuration mitigations. Remove or retain the AWS WAF rules as supporting controls after your fleet is patched.

Conclusion

The PHP2Shell vulnerabilities—CVE-2026-109618 and CVE-2026-109619—are unauthenticated RCE vulnerabilities that reach PHP before your application code runs. AWS WAF gives you a way to help narrow the attack surface during the patch window: block the session upload progress field, block multipart requests where no uploads are expected, cap request body size, and rate-limit repeated attempts. These mitigating controls can help reduce exposure, but they don’t close the vulnerabilities. Upgrade PHP to a fixed release, apply the server configuration changes, and treat the AWS WAF rules as the edge layer that supports those fixes rather than the fix itself.

To learn more about the rule types used here, see the AWS WAF documentation on the web ACL body inspection limit, oversize request component handling, and handling oversize HTTP request bodies. For the vulnerability details, see the PHP advisories GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp, and the PHP session upload progress manual.

Alex Waddell

Alex Waddell

Alex Waddell is a Principal Solutions Architect at AWS specializing in security within the Worldwide Specialist Organization, based in Scotland. Alex has been working in the security domain since 1999 and joined AWS in 2021 to work with customers across EMEA on cloud security architecture, identity, threat detection and application security. When he is not working, Alex enjoys spending time sampling rum from around the world (Alex is one of those rarely found Scottish people that doesn’t like whisky), walking his dogs in the local forest trails and traveling.

Lawton Pittenger

Lawton Pittenger

Lawton is a Worldwide Security Specialist Solutions Architect at AWS, based in New York City. He specializes in helping customers design and implement effective network security controls. At AWS, he works with customers at scale and collaborates closely with service teams to drive continuous improvement in security services based on customer needs and feedback. Outside of work, his interests include skateboarding, snowboarding, and spending time in nature.

Ian Olson

Ian Olson

Ian is a Senior Security Specialist Solutions Architect at AWS. He helps
customers automate security services to safeguard against threats like
DDoS and web exploitations. Through intelligent automation, he delivers
security solutions tailored to organizations of any scale. When he’s not
working, Ian enjoys spending quality time with his two young children.