May 5, 2026·6 min read·62 visits
A flaw in webonyx/graphql-php's parser allows attackers to crash the PHP process via highly nested GraphQL queries, bypassing application-level validation. The issue is fixed in version 15.32.3 by implementing a default recursion limit of 256.
An uncontrolled recursion vulnerability (CWE-674) in the webonyx/graphql-php library allows unauthenticated remote attackers to trigger a Denial of Service (DoS). The vulnerability resides in the recursive descent parser, which fails to limit the depth of nested structures, leading to a stack overflow and subsequent PHP process crash.
The webonyx/graphql-php library provides a robust PHP implementation of the GraphQL specification. It processes incoming GraphQL requests, parsing the query strings into an Abstract Syntax Tree (AST) before executing the requested operations against an application's data layer. This parsing phase is fundamental to the library's operation and handles all incoming user input automatically.
A vulnerability exists in the library's parser mechanism, specifically identified as CWE-674: Uncontrolled Recursion. The parser implements a recursive descent methodology to evaluate GraphQL document structures. Prior to version 15.32.3, this implementation lacked boundary limits on the depth of recursion it would permit during the initial lexical analysis.
When presented with a highly nested document structure, the parser enters an unconstrained recursive loop. This behavior exhausts the available call stack memory allocated to the executing process. The ensuing stack overflow results in an immediate denial of service condition by crashing the process handling the request.
The flaw resides within the Language\Parser class of the webonyx/graphql-php package. The parser translates standard GraphQL query strings into a programmatic AST representation. It maps specific structural elements of the GraphQL grammar, such as selection sets and type references, directly to recursive PHP method calls.
Key methods responsible for this recursive processing include parseSelectionSet(), parseValueLiteral(), and parseTypeReference(). Each method calls itself or a companion method to handle nested structures, such as a field requesting an inner object or a multi-dimensional array input. The structural design omitted state variables to track the current depth of this recursive descent.
As the parser descends into deeply nested structures, it continuously allocates new stack frames for each recursive method invocation. Once the number of frames exceeds the operating system's stack size limit for the PHP process, a memory access violation occurs. In PHP environments, this triggers a SIGSEGV (Signal 11), causing the entire process worker to terminate abruptly.
The vulnerability was remediated in commit 7b7f2080ca5f7d5340a696fc5701b19a9222d2c2. The patch addresses the root cause by introducing stateful depth tracking to the Language\Parser class. This mechanism actively monitors the recursion depth during the initial parsing phase and applies upper boundary limits.
The developers added a recursionDepth integer property to track the current depth, alongside a configurable recursionLimit property with a default value of 256. A new validation method, increaseRecursionDepth(), was introduced to increment the counter and enforce the maximum permitted depth. This method is now invoked at the entry points of all recursive loops within the parser architecture.
When the recursion limit is breached, the parser interrupts the execution flow by throwing a GraphQL\Error\SyntaxError. This architectural change converts an uncatchable process-level fault into a catchable application-level exception. The following snippet illustrates the core logic introduced in the fix:
private function increaseRecursionDepth(): void
{
if ($this->recursionLimit > 0 && $this->recursionDepth >= $this->recursionLimit) {
throw new SyntaxError(
$this->lexer->source,
$this->lexer->token->start,
"Recursion depth limit of {$this->recursionLimit} exceeded"
);
}
++$this->recursionDepth;
}Exploitation requires no authentication and relies on sending a single crafted HTTP request to the vulnerable GraphQL endpoint. The attacker must supply a query string containing artificially deep nesting. This nesting can be achieved using nested lists, recursive field selections, or layered type declarations within the payload.
The execution timing of the vulnerability significantly increases its severity. The stack overflow occurs during the lexical analysis and parsing phase. This phase strictly precedes the application of standard GraphQL validation rules, such as maximum query complexity scoring or explicit depth limits defined by the application layer framework.
Proof-of-concept payloads leverage standard GraphQL syntax repeated continuously. For example, deeply nested lists can be triggered via query ($var: [[[[[[[[Int]]]]]]]]) { field }. Similarly, deeply nested selections utilize recursive field structures like { a { a { a { ... } } } }. The parser attempts to resolve these structures entirely in memory, triggering the fault before returning a response.
A successful attack results in a Denial of Service (DoS) affecting the availability of the targeted application. The uncatchable SIGSEGV fault bypasses standard PHP error handling structures, including global exception handlers. This causes the executing PHP-FPM worker process or PHP CLI instance to terminate without returning an HTTP response or executing necessary clean-up routines.
Repeated exploitation systematically terminates available worker processes in the application server pool. If the attack rate exceeds the process manager's ability to spawn new replacement workers, the entire application becomes unresponsive to legitimate user traffic. This creates a high availability impact with minimal resource expenditure or network bandwidth requirements on the attacker's side.
Modern runtime protections mitigate some recursion issues but prove insufficient in this context. The zend.max_allowed_stack_size directive introduced in PHP 8.3 attempts to prevent segmentation faults by throwing an Error exception before the stack guard page is hit. However, in certain environment configurations, the raw depth of the GraphQL parser payload circumvents this check, making the application-level patch strictly necessary.
The primary remediation strategy requires updating the webonyx/graphql-php library to version 15.32.3 or later. This release introduces the required structural constraints to prevent uncontrolled recursion. System administrators and developers should execute composer update webonyx/graphql-php to deploy the fixed package to their environments.
Developers manually instantiating the Parser component must verify they do not inadvertently disable the new depth controls. The recursionLimit parameter defaults to 256, which provides ample margin for all legitimate GraphQL schemas. Explicitly setting this configuration to 0 removes the protection and re-exposes the application to the DoS vector.
In environments where immediate patching is unfeasible, administrators can deploy Web Application Firewall (WAF) rules as an interim mitigating control. These rules should explicitly block incoming payloads containing excessive consecutive structural characters, such as more than 100 sequential open brackets ([) or open braces ({). This heuristic approach successfully intercepts the fundamental structural prerequisite for the attack.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
graphql-php webonyx | < 15.32.3 | 15.32.3 |
| Attribute | Detail |
|---|---|
| Vulnerability Class | CWE-674: Uncontrolled Recursion |
| Attack Vector | Network (Unauthenticated) |
| Impact | High (Denial of Service via Process Crash) |
| Exploit Status | Proof of Concept Available |
| KEV Status | Not Listed |
| Affected Component | Language\Parser class |
The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack.
CVE-2026-63349 is a critical privilege-dropping bypass vulnerability in the AnyIO asynchronous framework (versions 4.14.0 and 4.14.1) on POSIX platforms. Due to a variable assignment typo, supplementary groups specified by the developer are not correctly propagated to the execution backend, resulting in subprocesses retaining the parent process's elevated supplementary group permissions.
CVE-2026-63406 is an information disclosure vulnerability in AnyCable-go prior to version 1.6.15. The built-in telemetry client is enabled by default with a hardcoded public authentication token ('secret'). This client digests highly sensitive configuration parameters and command-line arguments, including JWT secrets and RPC secrets, into a stable SHA-256 fingerprint. This fingerprint is sent over public networks, exposing those administrative secrets to offline dictionary and brute-force attacks if intercepted.
CVE-2026-84992 is a Cross-Site Scripting (XSS) vulnerability affecting md-editor-v3 before version 6.5.4. It occurs because the fenced-code block language parser directly interpolates unescaped language metadata into unquoted HTML attributes inside the custom rendering callback. This bypasses the built-in XSSPlugin which runs during the parsing phase, before rendering.
CVE-2026-81505 is a high-severity Broken Object Level Authorization (BOLA) / Insecure Direct Object Reference (IDOR) vulnerability in Convoy, a cloud-native webhooks gateway. In affected versions prior to 26.6.8, the single-item Source retrieval API endpoint authorizes project access but fails to confirm if the requested Source belongs to that specific project. This logical flaw allows authenticated users or project-scoped API key holders to bypass tenant isolation boundaries and retrieve unredacted, plaintext message broker credentials for Apache Kafka, Amazon SQS, RabbitMQ, and Google Cloud Pub/Sub belonging to other tenants. This issue is fully patched in version 26.6.8.
CVE-2026-77339 is a critical security vulnerability in Process Compose before version 1.120.0. The Model Context Protocol (MCP) Server-Sent Events (SSE) listener transport subsystem fails to validate the HTTP Host and Origin headers, and does not enforce authentication. This omissions expose local loopback listeners to DNS rebinding attacks orchestrated by malicious remote websites visited by developers, enabling unauthorized process control and arbitrary command execution.
CVE-2026-77301 is a critical uncontrolled resource allocation vulnerability in the popular Node.js library adm-zip (versions prior to 0.6.1). During ZIP decompression of asynchronous entries, the library trusts the uncompressed size metadata declared in the central directory headers. Because Node.js's streaming zlib API completely ignores the maxOutputLength configuration, a crafted ZIP archive (decompression bomb) causes the application to continually allocate resident memory buffers on the heap without limits, causing rapid memory exhaustion and a process-level Out-of-Memory (OOM) crash.