CVE-2026-119286
GraphQL-core: Denial of service via memory leak in aborted validations
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.3.0a3 until 3.3.1, validate() reuses a module-level ValidationAbortedError when a document exceeds max_errors. Python appends frames to the reused exception's traceback on every raise, retaining each document, validation context, and error set for the process lifetime. An unauthenticated client can repeatedly submit a small document with more than 100 validation errors to cause unbounded memory growth before query execution, eventually exhausting worker memory without disclosing or modifying data. This issue is fixed in version 3.3.1.
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 memory leak in aborted validations
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.3.0a3 until 3.3.1, validate() reuses a module-level ValidationAbortedError when a document exceeds max_errors. Python appends frames to the reused exception's traceback on every raise, retaining each document, validation context, and error set for the process lifetime. An unauthenticated client can repeatedly submit a small document with more than 100 validation errors to cause unbounded memory growth before query execution, eventually exhausting worker memory without disclosing or modifying data. This issue is fixed in version 3.3.1.
- Record
CVE-2026-119286- 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-401
- Updated
- 2026-11-02
EUVDEUVD-2026-113404
7.5
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.3.0a3 until 3.3.1, validate() reuses a module-level ValidationAbortedError when a document exceeds max_errors. Python appends frames to the reused exception's traceback on every raise, retaining each document, validation context, and error set for the process lifetime. An unauthenticated client can repeatedly submit a small document with more than 100 validation errors to cause unbounded memory growth before query execution, eventually exhausting worker memory without disclosing or modifying data. This issue is fixed in version 3.3.1.
- Record
EUVD-2026-113404- 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-mpqx-q82w-9x46
7.5
GraphQL-core has denial of service via memory leak in aborted validations
Summary
When a validation was aborted because the document contained more errors than allowed by max_errors (100 by default), validate() raised a single module-level ValidationAbortedError instance. Python appends the frames of every raise to the existing __traceback__ of an exception that is raised again, so every aborted validation extended the traceback of this shared error. That traceback kept the frames, and with them the document, the validation context and all errors of every aborted validation, alive for the lifetime of the process.
Details
Any client can trigger an aborted validation by sending a small document with more than 100 validation errors, e.g. 101 unknown fields. No authentication is required, and since validation runs before execution, depth limiters and complexity analyzers do not prevent it. Each such request permanently retained about 124 KiB on CPython 3.12, without an upper limit, so memory grew with every request until the process was restarted or killed.
GraphQL.js uses a shared error object at the same place, but JavaScript errors capture their stack trace only once when they are created, so it is not affected. GraphQL-core 3.2 creates a new error for each aborted validation and is not affected either.
Proof of concept
import gc
import tracemalloc
from graphql import build_schema, parse, validate
schema = build_schema("type Query { a: Int }")
document = parse("{ " + " ".join(f"f{i}" for i in range(101)) + " }")
tracemalloc.start()
validate(schema, document)
gc.collect()
base = tracemalloc.get_traced_memory()[0]
for _ in range(200):
validate(schema, document)
gc.collect()
print((tracemalloc.get_traced_memory()[0] - base) // 1024, "KiB")
With GraphQL-core 3.3.0 on CPython 3.12, the retained memory grows from 147 KiB after one call to about 25 MB after 200 calls. With the fix, it stays constant at about 180 KiB.
Impact
Denial of service through memory exhaustion. A few thousand small requests are enough to push a worker past a typical 256 MB or 512 MB container limit and trigger an OOM kill. No data is disclosed or modified.
Patches
Fixed in 3.3.1.
validate() now creates a new ValidationAbortedError for every aborted validation and removes its traceback and exception context before returning it, so that the returned errors do not keep the frames of the validation alive. The module-level validation_aborted_error instance, which was not exported, has been removed.
Workarounds
If you cannot upgrade, clear the traceback of the shared error after each validation:
from graphql.validation import validate as validate_document
from graphql.validation.validate import validation_aborted_error
def validate(*args, **kwargs):
try:
return validate_document(*args, **kwargs)
finally:
validation_aborted_error.__traceback__ = None
Pass this function instead of the original validate where your framework allows it.
Credits
Reported by @riodw. @Fire162 submitted a first fix in #288.
- Record
GHSA-mpqx-q82w-9x46- 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-401
- Updated
- 2026-11-02
NVD
7.5
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.3.0a3 until 3.3.1, validate() reuses a module-level ValidationAbortedError when a document exceeds max_errors. Python appends frames to the reused exception's traceback on every raise, retaining each document, validation context, and error set for the process lifetime. An unauthenticated client can repeatedly submit a small document with more than 100 validation errors to cause unbounded memory growth before query execution, eventually exhausting worker memory without disclosing or modifying data. This issue is fixed in version 3.3.1.
- Record
CVE-2026-119286- 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-401
- Updated
- 2026-11-02
OSV
7.5
GraphQL-core: Denial of service via memory leak in aborted validations
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.3.0a3 until 3.3.1, validate() reuses a module-level ValidationAbortedError when a document exceeds max_errors. Python appends frames to the reused exception's traceback on every raise, retaining each document, validation context, and error set for the process lifetime. An unauthenticated client can repeatedly submit a small document with more than 100 validation errors to cause unbounded memory growth before query execution, eventually exhausting worker memory without disclosing or modifying data. This issue is fixed in version 3.3.1.
- Record
CVE-2026-119286- 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-401
- Updated
- 2026-11-07
OSVGHSA-mpqx-q82w-9x46
7.5
GraphQL-core has denial of service via memory leak in aborted validations
Summary
When a validation was aborted because the document contained more errors than allowed by max_errors (100 by default), validate() raised a single module-level ValidationAbortedError instance. Python appends the frames of every raise to the existing __traceback__ of an exception that is raised again, so every aborted validation extended the traceback of this shared error. That traceback kept the frames, and with them the document, the validation context and all errors of every aborted validation, alive for the lifetime of the process.
Details
Any client can trigger an aborted validation by sending a small document with more than 100 validation errors, e.g. 101 unknown fields. No authentication is required, and since validation runs before execution, depth limiters and complexity analyzers do not prevent it. Each such request permanently retained about 124 KiB on CPython 3.12, without an upper limit, so memory grew with every request until the process was restarted or killed.
GraphQL.js uses a shared error object at the same place, but JavaScript errors capture their stack trace only once when they are created, so it is not affected. GraphQL-core 3.2 creates a new error for each aborted validation and is not affected either.
Proof of concept
import gc
import tracemalloc
from graphql import build_schema, parse, validate
schema = build_schema("type Query { a: Int }")
document = parse("{ " + " ".join(f"f{i}" for i in range(101)) + " }")
tracemalloc.start()
validate(schema, document)
gc.collect()
base = tracemalloc.get_traced_memory()[0]
for _ in range(200):
validate(schema, document)
gc.collect()
print((tracemalloc.get_traced_memory()[0] - base) // 1024, "KiB")
With GraphQL-core 3.3.0 on CPython 3.12, the retained memory grows from 147 KiB after one call to about 25 MB after 200 calls. With the fix, it stays constant at about 180 KiB.
Impact
Denial of service through memory exhaustion. A few thousand small requests are enough to push a worker past a typical 256 MB or 512 MB container limit and trigger an OOM kill. No data is disclosed or modified.
Patches
Fixed in 3.3.1.
validate() now creates a new ValidationAbortedError for every aborted validation and removes its traceback and exception context before returning it, so that the returned errors do not keep the frames of the validation alive. The module-level validation_aborted_error instance, which was not exported, has been removed.
Workarounds
If you cannot upgrade, clear the traceback of the shared error after each validation:
from graphql.validation import validate as validate_document
from graphql.validation.validate import validation_aborted_error
def validate(*args, **kwargs):
try:
return validate_document(*args, **kwargs)
finally:
validation_aborted_error.__traceback__ = None
Pass this function instead of the original validate where your framework allows it.
Credits
Reported by @riodw. @Fire162 submitted a first fix in #288.
- Record
GHSA-mpqx-q82w-9x46- 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-401
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-119286
7.5
GraphQL-core is a Python port of the GraphQL.js reference implementation. From 3.3.0a3 until 3.3.1, validate() reuses a module-level ValidationAbortedError when a document exceeds max_errors. Python appends frames to the reused exception's traceback on every raise, retaining each document, validation context, and error set for the process lifetime. An unauthenticated client can repeatedly submit a small document with more than 100 validation errors to cause unbounded memory growth before query execution, eventually exhausting worker memory without disclosing or modifying data. This issue is fixed in version 3.3.1.
- Record
UBUNTU-CVE-2026-119286- 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-05
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-119286 No score
CVE-2026-119286 in graphql-core - Patched by Root
Root has patched CVE-2026-119286 in the graphql-core package for Root:PyPI. Multiple fixed versions available.
- Record
ROOT-APP-PYPI-CVE-2026-119286- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
graphql-corePyPI |
3.3.0a3 up to 3.3.1 | 3.3.1 |
graphql-corePyPI |
3.3.0a3 up to 3.3.1, plus listed versions 3.3.03.3.0a103.3.0a113.3.0a123.3.0a13 Show 12 moreShow less3.3.0a143.3.0a43.3.0a53.3.0a63.3.0a73.3.0a83.3.0a93.3.0b03.3.0b13.3.0b23.3.0rc03.3.0rc1 |
3.3.1 |
graphql-coreRoot:PyPI |
before 3.3.0+aikido.1 | 3.3.0+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, references | OSV | |
| facts | 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-119286 is a high vulnerability (CVSS 7.5) in Graphql-python Graphql-core, published October 29, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.42%, the 36th percentile. Fixed in graphql-core 3.3.1.
References
github.com/graphql-python/graphql-core/security/advisories/GHSA-mpqx-q82w-9x46
github.com/graphql-python/graphql-core/issues/287
github.com/graphql-python/graphql-core/pull/288
github.com/graphql-python/graphql-core/commit/3c319fd9f4b8f6c9db4189520561bf8dd0e70be9
github.com/graphql-python/graphql-core/releases/tag/v3.3.1
nvd.nist.gov/vuln/detail/CVE-2026-119286
Show 8 moreShow less
github.com/advisories/GHSA-mpqx-q82w-9x46
github.com/CVEProject/cvelistV5/tree/main/cves/2026/119xxx/CVE-2026-119286.json
github.com/graphql-python/graphql-core
ubuntu.com/security/CVE-2026-119286
cve.org/CVERecord?id=CVE-2026-119286
suse.com/security/cve/CVE-2026-119286
suse.com/security/cve/CVE-2026-75507
suse.com/security/cve/CVE-2026-75508