Jun 4, 2026·5 min read·3 visits
The MaxAliasesLimiter extension in strawberry-graphql fails to account for fragment spreads during pre-execution static analysis. Attackers can bypass alias thresholds and trigger thousands of actual backend executions, leading to denial of service.
A security flaw in strawberry-graphql versions 0.172.0 through 0.315.6 allows unauthenticated attackers to bypass the MaxAliasesLimiter extension. By utilizing GraphQL fragment spreads, clients can trigger high levels of alias amplification, causing uncontrolled backend resource consumption and application-level Denial of Service.
In GraphQL architectures, the concept of aliasing allows clients to customize field names within a single payload. This feature allows multiple variants of the same field to be queried simultaneously. However, resolving thousands of aliases simultaneously consumes excessive CPU and memory on the backend engine. To mitigate this threat vector, developers use security extensions to enforce constraints on the maximum allowed aliases.
The strawberry-graphql library provides a native MaxAliasesLimiter extension designed to limit client-defined aliases. In versions prior to 0.315.7, this validation module failed to assess the impact of fragment spreads. Attackers can exploit this architectural oversight to cause application-level denial of service via uncontrolled resource consumption.
The vulnerability stems from an inconsistency between static analysis and actual execution behavior. The MaxAliasesLimiter calculates alias counts by analyzing the static syntax elements in the Abstract Syntax Tree (AST) before runtime. During this inspection, it aggregates explicitly defined aliases inside structural definitions, such as operations and fragment blocks.
The validator, however, failed to expand FragmentSpreadNode elements inline during counting. If a fragment definition containing N aliases is spread M times in an operation, the execution engine multiplies these selections to produce N x M alias resolutions.
Because the validator calculated the aliases statically and independently within each distinct AST definition node, it did not model this multiplicative expansion. The static validation path evaluated the fragment definition once and the operation once, registering a linear total of N + M instead of N x M. This difference allows an attacker to bypass arbitrary alias thresholds.
Prior to the release of 0.315.7, the implementation of count_fields_with_alias in strawberry/extensions/max_aliases.py was structurally limited. The function analyzed selection_set_owner elements without any visibility into the broader Document definitions. It could not resolve FragmentSpreadNode occurrences back to their associated fragment contents.
# Vulnerable implementation in strawberry/extensions/max_aliases.py
for selection in selection_set_owner.selection_set.selections:
if isinstance(selection, FieldNode) and selection.alias:
result += 1
if isinstance(selection, (FieldNode, InlineFragmentNode)):
result += count_fields_with_alias(selection)The patch introduces a dictionary mapping fragment names to their corresponding definitions within the validator initialization. The revised count_fields_with_alias function takes this lookup map along with a visited_fragments tracker to safely recurse into spread fragments.
# Patched implementation in strawberry/extensions/max_aliases.py
if isinstance(selection, FragmentSpreadNode) and fragments:
fragment_name = selection.name.value
fragment = fragments.get(fragment_name)
if fragment is None or fragment_name in visited_fragments:
continue
result += count_fields_with_alias(
fragment,
fragments,
visited_fragments | {fragment_name},
)Additionally, the patch applies similar visited-fragment state tracking to the query depth evaluation engine in strawberry/extensions/query_depth_limiter.py. This change ensures that cycle validation prevents infinite loops from crashing the validation layer during the resolution of deeply nested fragment loops.
To demonstrate the exploitation vector, a security researcher can construct an operational bypass of a low alias limit. Consider a target backend configuring the MaxAliasesLimiter with a maximum limit of twenty total aliases. An attacker can define a single fragment containing ten distinct aliased fields on a target type.
The attacker then queries a single entity ten times inside a single operational selection set, spreading the defined fragment in each invocation.
fragment Amplification on User {
a1: name, a2: name, a3: name, a4: name, a5: name,
a6: name, a7: name, a8: name, a9: name, a10: name
}
query Bypass {
u1: user { ...Amplification }
u2: user { ...Amplification }
u3: user { ...Amplification }
u4: user { ...Amplification }
u5: user { ...Amplification }
u6: user { ...Amplification }
u7: user { ...Amplification }
u8: user { ...Amplification }
u9: user { ...Amplification }
u10: user { ...Amplification }
}At evaluation time, the static analyzer registers the ten aliases in the fragment definition and the ten selection fields in the operation. This registers a calculated sum of twenty aliases, which exactly matches the threshold.
When executed, the engine expands the ten fragment fields across the ten operation fields, yielding 110 alias resolutions. This execution completely bypasses the configured security policy.
Although the official patch resolves the primary alias amplification bypass, security reviewers must consider remaining architectural edge cases. Specifically, count_fields_with_alias executes recursively using Python's native runtime call stack. A deeply nested, non-cyclic chain of fragment spreads could theoretically trigger a native RecursionError if it exceeds the default system recursion limit.
Furthermore, because the cycle prevention tracker uses an active execution branch state (visited_fragments | {fragment_name}), a non-cyclic Directed Acyclic Graph (DAG) can still bypass validation-phase loop protections. An attacker can structure exponential layout patterns known as "GraphQL Billion Laughs" structures.
For example, defining twenty-five layers of nested binary fragments will scale validation logic to over thirty-three million operations. This causes the Python process to hang indefinitely on the synchronous validation thread, achieving CPU exhaustion.
To remediate this vulnerability, system administrators must immediately upgrade strawberry-graphql deployments to version 0.315.7 or higher. The patch updates both alias calculation paths and depth evaluation rules to prevent unconstrained amplification attacks.
Where immediate upgrades are not feasible, organizations can temporarily disable the MaxAliasesLimiter extension. To compensate, developers should implement alternate GraphQL document structural checks. Deploying specialized application firewalls or utilizing standard schema complexity validation rules from alternative libraries is highly recommended.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
strawberry-graphql Strawberry GraphQL | >= 0.172.0, < 0.315.7 | 0.315.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 (Uncontrolled Resource Consumption) |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 | 5.3 (Medium) |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
| Primary Impact | Availability (Application-level Denial of Service) |
The software does not properly control the allocation and maintenance of a limited resource, enabling an actor to cause resource exhaustion.
An application-level Denial of Service vulnerability exists in the Strawberry GraphQL library (versions 0.71.0 through 0.315.6) due to uncontrolled recursion within the QueryDepthLimiter and MaxAliasesLimiter extensions when processing circular fragment references.
React Router and the underlying turbo-stream vendor library contain a vulnerability allowing remote unauthenticated attackers to trigger a Denial of Service (DoS) or potentially client-side Cross-Site Scripting (XSS) due to unsafe dynamic deserialization of streaming error payloads.
CVE-2026-48710 is a critical security-desynchronization vulnerability in the Starlette ASGI framework (versions >= 0.8.3, < 1.0.1) that allows remote attackers to bypass path-based security middleware and access-control decorators. By injecting URI authority-to-path delimiters into the Host header, attackers can manipulate the application-level parsed URL path while the underlying ASGI server dispatches the request to target endpoints.
CVE-2026-20230 is a critical Server-Side Request Forgery (SSRF) vulnerability in the WebDialer service of Cisco Unified Communications Manager (Unified CM) and Cisco Unified Communications Manager Session Management Edition (Unified CM SME). The flaw arises from improper validation of input parameters within WebDialer HTTP requests. Unauthenticated remote attackers can exploit this vulnerability to force the application to make HTTP requests to internal administrative services bound to the loopback interface. In the Cisco Voice Operating System (VOS) environment, these local services trust loopback traffic inherently, permitting unauthorized file writes. By writing malicious files to specific system directories, the attacker can execute arbitrary commands with root privileges.
CVE-2026-48526 is an algorithm-confusion vulnerability in PyJWT prior to version 2.13.0. When an application decodes tokens using a raw JSON Web Key (JWK) string while simultaneously supporting mixed algorithm families (symmetric and asymmetric), PyJWT does not validate that the key matches its intended algorithm context. This allows an attacker to sign a forged token using the public JWK string as an HMAC symmetric secret, bypassing authentication controls.
CVE-2026-23479 is a critical Use-After-Free (UAF) vulnerability inside the blocking-client code path of the Redis in-memory data structure server. In affected versions from 7.2.0 until 8.6.3, the unblock client flow fails to handle an error return from processCommandAndResetClient when re-executing a previously blocked command. If a blocked client is evicted due to maxmemory limits or client eviction policies during this command processing flow, its client structure is freed. Because the caller ignores the error return and continues processing, it attempts to read and write properties on the freed client structure, leading to a Use-After-Free condition.