CVE-2026-75507
GraphQL-core: Denial of service via quadratic complexity in the OverlappingFieldsCanBeMerged validation rule
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.0.0 until 3.2.12 and 3.3.0rc1, the OverlappingFieldsCanBeMerged rule in specified_rules repeatedly compares fields that share response names and recursively re-compares flattened inline fragments during the validation phase. The prior named-fragment memoization does not cover this path, so nested repeated inline fragments can drive quadratic and worst-case O(n²·m²) CPU work before any resolver or AST-based depth or complexity control runs. An unauthenticated remote attacker can submit a shallow, highly compressible GraphQL query that pins a worker process and can saturate a multi-worker service. This issue is fixed in versions 3.2.12 and 3.3.0rc1.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
GraphQL-core: Denial of service via quadratic complexity in the OverlappingFieldsCanBeMerged validation rule
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.0.0 until 3.2.12 and 3.3.0rc1, the OverlappingFieldsCanBeMerged rule in specified_rules repeatedly compares fields that share response names and recursively re-compares flattened inline fragments during the validation phase. The prior named-fragment memoization does not cover this path, so nested repeated inline fragments can drive quadratic and worst-case O(n²·m²) CPU work before any resolver or AST-based depth or complexity control runs. An unauthenticated remote attacker can submit a shallow, highly compressible GraphQL query that pins a worker process and can saturate a multi-worker service. This issue is fixed in versions 3.2.12 and 3.3.0rc1.
- Record
CVE-2026-75507- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-407
- Updated
- 2026-11-02
EUVDEUVD-2026-108226
7.5
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.0.0 until 3.2.12 and 3.3.0rc1, the OverlappingFieldsCanBeMerged rule in specified_rules repeatedly compares fields that share response names and recursively re-compares flattened inline fragments during the validation phase. The prior named-fragment memoization does not cover this path, so nested repeated inline fragments can drive quadratic and worst-case O(n²·m²) CPU work before any resolver or AST-based depth or complexity control runs. An unauthenticated remote attacker can submit a shallow, highly compressible GraphQL query that pins a worker process and can saturate a multi-worker service. This issue is fixed in versions 3.2.12 and 3.3.0rc1.
- Record
EUVD-2026-108226- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-vj8h-fx38-h3vc
7.5
GraphQL-core: Denial of service via quadratic complexity in the OverlappingFieldsCanBeMerged validation rule
Summary
The OverlappingFieldsCanBeMerged validation rule can be driven into quadratic — and
in the worst case O(n²·m²) — running time by a small, highly compressible query. A
single 364 KB document can occupy one CPU core for over five minutes during
validation, before any resolver runs. Because the rule is part of specified_rules
and therefore enabled by default, every GraphQL-core based server is affected at
default settings.
Details
OverlappingFieldsCanBeMerged compares every pair of fields that share a response
name and recurses into their sub-selections. The memoization added for
CVE-2023-26144 (GHSA-9pv7-vfvm-6vr7) is keyed by named fragment identity, so it
does not cover this path: inline fragments are flattened into the parent selection
set before the cache is consulted, and therefore every pair is re-compared from
scratch at every nesting level.
Repeating an inline fragment that selects the same response name at two nesting levels multiplies the two effects. There was no comparison budget and no validation timeout, so the rule ran to completion regardless of cost.
The cost is incurred in the validation phase, which is what makes this hard to defend against from outside the library: query-depth limiters, complexity analyzers and cost estimators all operate on the parsed document after validation, and the malicious document is trivially shallow (depth 3, complexity 1). The payload is also one short string repeated many times, so it compresses to a few kilobytes and slips past body-size limits and WAF inspection that only see the compressed request.
Proof of concept
import time
from graphql import build_schema, parse, validate
schema = build_schema(
"type Query { field: Node } type Node { f: Node, g: Node, x: String }"
)
def gen(n: int, m: int) -> str:
inner = " ".join(["... on Node { x }"] * m)
outer = " ".join([f"... on Node {{ f {{ {inner} }} }}"] * n)
return f"{{ field {{ {outer} }} }}"
query = gen(200, 100) # 364 KB, gzips to a few KB
document = parse(query)
start = time.perf_counter()
validate(schema, document) # returns no errors — it just burns CPU
print(f"{(time.perf_counter() - start):.0f}s")
Measured on GraphQL-core 3.2.8 / CPython 3.12 / Linux x86_64:
| n | m | query size | validation time | |---|---|---|---| | 20 | 20 | 7.6 KB | 0.16 s | | 50 | 50 | 46 KB | 5.2 s | | 100 | 100 | 182 KB | 81 s | | 200 | 100 | 364 KB | 319 s |
Doubling n at fixed m quadruples the time, as expected for a quadratic outer loop
driving a quadratic inner walk.
Impact
Denial of service. One request pins one worker process for minutes; because CPython holds the GIL for this pure-CPU work, a handful of concurrent requests can saturate a typical multi-worker deployment. No authentication is required, and no data is disclosed or modified.
Patches
Fixed in 3.2.12 and 3.3.0rc1.
Validation now enforces a per-document comparison budget. Once
MAX_FIELD_COMPARISONS (default 250_000) pairwise comparisons have been made, the
rule aborts and reports a GraphQLError instead of running to completion:
Query is too complex to validate for overlapping fields: exceeded 250000 field comparisons. Validation was aborted.
The default is far above what any realistic query reaches. It is a module-level constant and can be raised or lowered:
from graphql.validation.rules import overlapping_fields_can_be_merged
overlapping_fields_can_be_merged.MAX_FIELD_COMPARISONS = 1_000_000
Note the behaviour change: a pathological query that previously validated — slowly — now produces a validation error.
Workarounds
If you cannot upgrade, reject oversized documents before they reach validate().
Note that a request body-size limit must be applied to the decompressed body to be
effective here, since the payload is highly compressible. Removing
OverlappingFieldsCanBeMergedRule from the rule set is…
- Record
GHSA-vj8h-fx38-h3vc- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-407
- Updated
- 2026-11-02
NVD
7.5
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.0.0 until 3.2.12 and 3.3.0rc1, the OverlappingFieldsCanBeMerged rule in specified_rules repeatedly compares fields that share response names and recursively re-compares flattened inline fragments during the validation phase. The prior named-fragment memoization does not cover this path, so nested repeated inline fragments can drive quadratic and worst-case O(n²·m²) CPU work before any resolver or AST-based depth or complexity control runs. An unauthenticated remote attacker can submit a shallow, highly compressible GraphQL query that pins a worker process and can saturate a multi-worker service. This issue is fixed in versions 3.2.12 and 3.3.0rc1.
- Record
CVE-2026-75507- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-407
- Updated
- 2026-11-02
OSV
7.5
GraphQL-core: Denial of service via quadratic complexity in the OverlappingFieldsCanBeMerged validation rule
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.0.0 until 3.2.12 and 3.3.0rc1, the OverlappingFieldsCanBeMerged rule in specified_rules repeatedly compares fields that share response names and recursively re-compares flattened inline fragments during the validation phase. The prior named-fragment memoization does not cover this path, so nested repeated inline fragments can drive quadratic and worst-case O(n²·m²) CPU work before any resolver or AST-based depth or complexity control runs. An unauthenticated remote attacker can submit a shallow, highly compressible GraphQL query that pins a worker process and can saturate a multi-worker service. This issue is fixed in versions 3.2.12 and 3.3.0rc1.
- Record
CVE-2026-75507- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-407
- Updated
- 2026-11-07
OSVDEBIAN-CVE-2026-75507
7.5
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.0.0 until 3.2.12 and 3.3.0rc1, the OverlappingFieldsCanBeMerged rule in specified_rules repeatedly compares fields that share response names and recursively re-compares flattened inline fragments during the validation phase. The prior named-fragment memoization does not cover this path, so nested repeated inline fragments can drive quadratic and worst-case O(n²·m²) CPU work before any resolver or AST-based depth or complexity control runs. An unauthenticated remote attacker can submit a shallow, highly compressible GraphQL query that pins a worker process and can saturate a multi-worker service. This issue is fixed in versions 3.2.12 and 3.3.0rc1.
- Record
DEBIAN-CVE-2026-75507- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
Show 4 moreShow less
OSVGHSA-vj8h-fx38-h3vc
7.5
GraphQL-core: Denial of service via quadratic complexity in the OverlappingFieldsCanBeMerged validation rule
Summary
The OverlappingFieldsCanBeMerged validation rule can be driven into quadratic — and
in the worst case O(n²·m²) — running time by a small, highly compressible query. A
single 364 KB document can occupy one CPU core for over five minutes during
validation, before any resolver runs. Because the rule is part of specified_rules
and therefore enabled by default, every GraphQL-core based server is affected at
default settings.
Details
OverlappingFieldsCanBeMerged compares every pair of fields that share a response
name and recurses into their sub-selections. The memoization added for
CVE-2023-26144 (GHSA-9pv7-vfvm-6vr7) is keyed by named fragment identity, so it
does not cover this path: inline fragments are flattened into the parent selection
set before the cache is consulted, and therefore every pair is re-compared from
scratch at every nesting level.
Repeating an inline fragment that selects the same response name at two nesting levels multiplies the two effects. There was no comparison budget and no validation timeout, so the rule ran to completion regardless of cost.
The cost is incurred in the validation phase, which is what makes this hard to defend against from outside the library: query-depth limiters, complexity analyzers and cost estimators all operate on the parsed document after validation, and the malicious document is trivially shallow (depth 3, complexity 1). The payload is also one short string repeated many times, so it compresses to a few kilobytes and slips past body-size limits and WAF inspection that only see the compressed request.
Proof of concept
import time
from graphql import build_schema, parse, validate
schema = build_schema(
"type Query { field: Node } type Node { f: Node, g: Node, x: String }"
)
def gen(n: int, m: int) -> str:
inner = " ".join(["... on Node { x }"] * m)
outer = " ".join([f"... on Node {{ f {{ {inner} }} }}"] * n)
return f"{{ field {{ {outer} }} }}"
query = gen(200, 100) # 364 KB, gzips to a few KB
document = parse(query)
start = time.perf_counter()
validate(schema, document) # returns no errors — it just burns CPU
print(f"{(time.perf_counter() - start):.0f}s")
Measured on GraphQL-core 3.2.8 / CPython 3.12 / Linux x86_64:
| n | m | query size | validation time | |---|---|---|---| | 20 | 20 | 7.6 KB | 0.16 s | | 50 | 50 | 46 KB | 5.2 s | | 100 | 100 | 182 KB | 81 s | | 200 | 100 | 364 KB | 319 s |
Doubling n at fixed m quadruples the time, as expected for a quadratic outer loop
driving a quadratic inner walk.
Impact
Denial of service. One request pins one worker process for minutes; because CPython holds the GIL for this pure-CPU work, a handful of concurrent requests can saturate a typical multi-worker deployment. No authentication is required, and no data is disclosed or modified.
Patches
Fixed in 3.2.12 and 3.3.0rc1.
Validation now enforces a per-document comparison budget. Once
MAX_FIELD_COMPARISONS (default 250_000) pairwise comparisons have been made, the
rule aborts and reports a GraphQLError instead of running to completion:
Query is too complex to validate for overlapping fields: exceeded 250000 field comparisons. Validation was aborted.
The default is far above what any realistic query reaches. It is a module-level constant and can be raised or lowered:
from graphql.validation.rules import overlapping_fields_can_be_merged
overlapping_fields_can_be_merged.MAX_FIELD_COMPARISONS = 1_000_000
Note the behaviour change: a pathological query that previously validated — slowly — now produces a validation error.
Workarounds
If you cannot upgrade, reject oversized documents before they reach validate().
Note that a request body-size limit must be applied to the decompressed body to be
effective here, since the payload is highly compressible. Removing
OverlappingFieldsCanBeMergedRule from the rule set is…
- Record
GHSA-vj8h-fx38-h3vc- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-407
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-75507
7.5
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.0.0 until 3.2.12 and 3.3.0rc1, the OverlappingFieldsCanBeMerged rule in specified_rules repeatedly compares fields that share response names and recursively re-compares flattened inline fragments during the validation phase. The prior named-fragment memoization does not cover this path, so nested repeated inline fragments can drive quadratic and worst-case O(n²·m²) CPU work before any resolver or AST-based depth or complexity control runs. An unauthenticated remote attacker can submit a shallow, highly compressible GraphQL query that pins a worker process and can saturate a multi-worker service. This issue is fixed in versions 3.2.12 and 3.3.0rc1.
- Record
UBUNTU-CVE-2026-75507- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
OSVopenSUSE-SU-2026:12474-1 No score
python313-graphql-core-3.3.1-1.1 on GA media
These are all security issues fixed in the python313-graphql-core-3.3.1-1.1 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2026:12474-1- Updated
- 2026-11-07
OSVROOT-APP-PYPI-CVE-2026-75507 No score
CVE-2026-75507 in graphql-core - Patched by Root
Root has patched CVE-2026-75507 in the graphql-core package for Root:PyPI. Multiple fixed versions available.
- Record
ROOT-APP-PYPI-CVE-2026-75507- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
graphql-corePyPI |
3.0.0 up to 3.2.12 | 3.2.12 |
graphql-corePyPI |
3.3.0a1 up to 3.3.0rc1 | 3.3.0rc1 |
graphql-coreDebian:12 |
All versions, plus listed versions 2.3.2-13.1.7-13.2.0-13.2.1-13.2.11-1 Show 9 moreShow less3.2.12-13.2.3-13.2.3-23.2.4-13.2.5-13.2.6-13.2.6-23.2.7-13.2.8-1 |
None known |
graphql-coreDebian:13 |
All versions, plus listed versions 3.2.11-13.2.12-13.2.6-13.2.6-23.2.7-13.2.8-1 |
None known |
graphql-coreDebian:14 |
before 3.2.12-1, plus listed versions 3.2.11-13.2.6-13.2.6-23.2.7-13.2.8-1 |
3.2.12-1 |
graphql-corePyPI |
3.0.0 up to 3.2.12, plus listed versions 3.0.13.0.23.0.33.0.43.0.5 Show 29 moreShow less3.0.63.1.03.1.0b03.1.0b13.1.0b23.1.13.1.23.1.33.1.43.1.53.1.63.1.73.2.03.2.0rc13.2.0rc23.2.0rc33.2.0rc43.2.0rc53.2.13.2.103.2.113.2.23.2.33.2.43.2.53.2.63.2.73.2.83.2.9 |
3.2.12 |
graphql-corePyPI |
3.3.0a1 up to 3.3.0rc1, plus listed versions 3.3.0a103.3.0a113.3.0a123.3.0a133.3.0a14 Show 12 moreShow less3.3.0a23.3.0a33.3.0a43.3.0a53.3.0a63.3.0a73.3.0a83.3.0a93.3.0b03.3.0b13.3.0b23.3.0rc0 |
3.3.0rc1 |
graphql-coreRoot:PyPI |
before 3.2.11+aikido.1 | 3.2.11+aikido.13.2.6+aikido.1 |
graphql-coreUbuntu:22.04:LTS |
All versions, plus listed versions 2.3.2-1 |
None known |
graphql-coreUbuntu:24.04:LTS |
All versions, plus listed versions 3.2.3-2 |
None known |
graphql-coreUbuntu:26.10 |
All versions, plus listed versions 3.2.7-13.2.8-13.2.11-1 |
None known |
graphql-coreUbuntu:26.04:LTS |
All versions, plus listed versions 3.2.6-13.2.6-23.2.7-1 |
None known |
python-graphql-coreopenSUSE:Tumbleweed From an advisory covering 3 CVEs |
before 3.3.1-1.1 | 3.3.1-1.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, aliases, facts, references | OSV | |
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-75507 is a high vulnerability (CVSS 7.5) in Graphql-python Graphql-core, published October 22, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.60%, the 48th percentile. Fixed in graphql-core 3.2.12.
References
github.com/graphql-python/graphql-core/security/advisories/GHSA-vj8h-fx38-h3vc
github.com/graphql-python/graphql-core/commit/150e59814d97d12140be005a558c93188ef89198
github.com/graphql-python/graphql-core/commit/29c2753a7ee30a96a4109e7c6add1a2dae0497d7
github.com/graphql-python/graphql-core/releases/tag/v3.2.12
github.com/graphql-python/graphql-core/releases/tag/v3.3.0rc1
github.com/advisories/GHSA-vj8h-fx38-h3vc
Show 9 moreShow less
github.com/CVEProject/cvelistV5/tree/main/cves/2026/75xxx/CVE-2026-75507.json
nvd.nist.gov/vuln/detail/CVE-2026-75507
security-tracker.debian.org/tracker/CVE-2026-75507
github.com/graphql-python/graphql-core
ubuntu.com/security/CVE-2026-75507
cve.org/CVERecord?id=CVE-2026-75507
suse.com/security/cve/CVE-2026-119286
suse.com/security/cve/CVE-2026-75507
suse.com/security/cve/CVE-2026-75508
Left out here: the rest of 2 source descriptions. The JSON record has them.