Skip to content
MAGEKWIKScanner
high CVE-2026-40476 CVSS 6.9

Magento GraphQL: introspection exposure and query-complexity DoS

Magekwik Security 6 min read

HARDENING CVE-2026-40476 CVSS 6.9 scan.magekwik.com

Magento's /graphql endpoint answers introspection in production and rides on webonyx/graphql-php, whose OverlappingFieldsCanBeMerged validator can degrade to quadratic time — a single crafted inline-fragment query can burn a php-fpm worker before any resolver runs. The mechanism, how to detect it, and the isolated patch chain.

What it is

Two related exposures sit on the Magento GraphQL endpoint (/graphql). The first is a misconfiguration: schema introspection is answerable in production, so any anonymous client can dump the entire type system. The second is a class of algorithmic-complexity denial of service in webonyx/graphql-php — the library Adobe Commerce bundles as its GraphQL runtime — where query validation runs in quadratic time and turns one small request into seconds of pinned CPU. Chained, an attacker reads the schema, then hand-crafts requests that exhaust the php-fpm pool before a single resolver executes.

Root cause

Introspection has been answerable in production mode since 2.3.2; the endpoint resolves __schema and __type for unauthenticated callers by default. That is intended behaviour, not a bug — but it is rarely what an operator wants facing the open internet.

The DoS root cause is deeper. Magento ships Magento\Framework\GraphQl\Query\QueryComplexityLimiter with defaults of queryComplexity: 300 and queryDepth: 20. Those counters score fields. They do not model the cost inside graphql-php's OverlappingFieldsCanBeMerged validation rule, which compares selected fields pairwise and runs before complexity gating meaningfully protects you. When many fields share a response name, the comparison degrades to O(n²); nested inline fragments compound it to roughly O(n² × m²). The original quadratic bug was tracked upstream in graphql-js (the JavaScript reference implementation) as CVE-2023-26144; graphql-php later ported the same rule and its memoization fix — but that memoization only covered named fragments, leaving inline fragments as an open bypass.

How attackers abuse it

  • Send a standard introspection query to enumerate every type, custom-module field, mutation name, and deprecated field — reconnaissance for targeted resolver abuse.
  • Use aliasing and batching to multiply resolver work while staying under the complexity ceiling.
  • Trigger the validator pathology directly. A ~364 KB query built from 200 outer and 100 inner inline fragments selecting identical response names consumes ~117 seconds of CPU during validation alone — no resolver reached, no timeout fired.
  • Each such request occupies one full worker. Against a typical php-fpm pool of 5–50 workers, a handful of parallel requests pins the pool. The body is sent gzip-compressed, so naive request-size limits at the edge decompress it and pass it straight to the validator.

Who got hit / real examples

This is a live, cataloged vulnerability chain in the exact library Adobe Commerce depends on via Composer — so it lands on any storefront running an unpatched vendor tree, regardless of custom code.

OverlappingFieldsCanBeMerged DoS timeline (graphql-js → graphql-php)

  • CVE-2023-26144 — the ORIGINAL quadratic OverlappingFieldsCanBeMerged cost, in graphql-js (npm graphql 16.3.0–<16.8.1), fixed with named-fragment memoization. Magento's graphql-php later inherited the same rule.
  • CVE-2026-40476 (GHSA-68jq-c3rv-pcrr) — quadratic cost on repeated same-response-name fields. Affected ≤ 15.31.4, fixed in 15.31.5. CVSS 6.9. Disclosed 2026-04-11.
  • GHSA-fc86-6rv6-2jpm — the inline-fragment bypass of the prior fix. Affected < 15.32.2, fixed in 15.32.2. CVSS 7.5 (availability impact High). Disclosed 2026-04-24.

How to check

Is introspection answerable in production?
curl -s https://store.example.com/graphql \
  -H 'Content-Type: application/json' \
  -d '{"query":"{ __schema { queryType { name } types { name } } }"}' \
  | head -c 400
# A populated __schema.types array = introspection is open.
Which graphql-php is actually installed?
composer show webonyx/graphql-php | grep versions
# Anything below 15.32.2 is exposed to the inline-fragment DoS.
composer why webonyx/graphql-php   # confirms it comes via magento/framework

Also confirm whether anyone has overridden the limiter defaults — grep your di.xml tree for QueryComplexityLimiter. If the defaults are untouched, depth 20 / complexity 300 is all that stands between you and resolver amplification.

How to fix it

  1. Patch the dependency first. This is the isolated, highest-value fix — it closes the CVE chain without touching your own code.
  2. Disable introspection at the edge or in config for production.
  3. Tighten the limiter and cap request body size on /graphql, including compressed bodies.
Update the bundled validator
composer update webonyx/graphql-php --with-dependencies
# Target >= 15.32.2. On Adobe Commerce, apply the corresponding
# vendor patch via the Quality Patches Tool rather than editing vendor/.
Disable introspection in production (env.php)
'graphql' => [
    'disable_introspection' => true,
],
Lower the complexity/depth ceiling (app/etc/di.xml)
&lt;type name="Magento\Framework\GraphQl\Query\QueryComplexityLimiter"&gt;
    &lt;arguments&gt;
        &lt;argument name="queryDepth" xsi:type="number"&gt;10&lt;/argument&gt;
        &lt;argument name="queryComplexity" xsi:type="number"&gt;150&lt;/argument&gt;
    &lt;/arguments&gt;
&lt;/type&gt;

At the edge, put a hard client_max_body_size on the /graphql location and rate-limit it independently of the rest of the store — a legitimate storefront query is kilobytes, not hundreds of kilobytes. Body-size and rate limits are the durable control here, because complexity scoring alone never sees the validator cost that these CVEs exploit.

References & sources

Primary sources — advisories, vendor research, and the CVE record. Verify against these, not us.

  1. GHSA-fc86-6rv6-2jpm — quadratic validation via inline fragments
  2. CVE-2026-40476 / GHSA-68jq-c3rv-pcrr — OverlappingFieldsCanBeMerged quadratic DoS
  3. Adobe Commerce — GraphQL security configuration
  4. magento/devdocs #3717 — introspection allowed in production
  5. Snyk — CVE-2023-26144 DoS in graphql (graphql-js origin)

← All security posts