CVE Patch Review

CVE-2026-47707: Root-Cause Fix for Strawberry MaxAliasesLimiter Fragment Spread Bypass

CVE-2026-47707 · Updated 2026-06-05 Root-cause

Summary

The patch addresses the core counting flaw in Strawberry GraphQL's MaxAliasesLimiter by expanding fragment spreads during static alias analysis and preventing recursive fragment traversal from looping indefinitely. The accompanying tests demonstrate both the original bypass condition and the recursion safety behavior. Based on the supplied diff, this is a root-cause fix for the alias amplification issue described in the CVE.

Analysis

Vulnerability

CVE-2026-47707 describes a denial-of-service condition in Strawberry GraphQL's MaxAliasesLimiter: pre-execution static analysis counted aliases only in the immediate operation tree and did not expand aliases introduced through fragment spreads. In GraphQL, a fragment can be reused multiple times, so undercounting aliases at validation time allows a query to appear cheap while causing many more effective field resolutions at execution time. The release notes in the upstream patch explicitly state that MaxAliasesLimiter now expands fragment spreads when counting aliases, so aliases declared inside fragments are counted each time the fragment is used, which matches the reported bypass mechanism in the CVE record and patch summary.

The same patch series also updates QueryDepthLimiter to track visited fragments, indicating a related class of static-analysis weakness around fragment traversal. That matters here because any fix that recursively expands fragments must also avoid unbounded recursion on cyclic fragment graphs. The added tests show both the exploit shape for repeated fragment spreads and the recursion edge case. Sources: official patch commit, NVD, CVE record.

fragment humanInfo on Human {
  email_address: email
  full_name: name
}
query read {
  matt: user(name: "matt") {
    ...humanInfo
  }
  jane: user(name: "jane") {
    ...humanInfo
  }
}

This test case from the patch is the essential exploit model: two top-level aliases plus two aliases inside a fragment reused twice yields six effective aliases, not four.

Patch

The patch modifies strawberry/extensions/max_aliases.py so alias counting is no longer limited to direct selections. It now builds a fragment map from document.definitions, passes that map into the counting routine, and recursively expands FragmentSpreadNode references. It also introduces a visited_fragments set to prevent infinite recursion when fragments are cyclic.

fragments = {
    definition.name.value: definition
    for definition in document.definitions
    if isinstance(definition, FragmentDefinitionNode)
}

...

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},
    )

This is the critical behavioral change: aliases inside fragments are counted at each spread site, which closes the amplification gap. The use of visited_fragments ensures the traversal terminates even if the query contains recursive fragment references.

The patch also updates strawberry/extensions/query_depth_limiter.py with the same visited-fragment pattern. While that file is not the direct CVE target, it is relevant because both extensions perform static traversal over GraphQL AST structures and both were vulnerable to fragment-related analysis errors. The release notes confirm both fixes in one release: official patch commit.

Test coverage was expanded in tests/schema/extensions/test_max_aliases.py to assert that repeated fragment spreads count expanded aliases and that circular fragment spreads do not recurse forever. Additional depth-limiter tests validate recursion safety independently.

Review

Pros

  • The fix addresses the actual counting model mismatch rather than merely tightening a threshold. Fragment spreads are expanded during analysis, which is the correct semantic behavior for alias accounting.
  • The implementation is localized and low-complexity: a fragment definition map plus recursive traversal with cycle detection.
  • The added visited_fragments guard is an important correctness and availability improvement. Without it, a fragment-expansion fix could itself introduce a parser/validator DoS on cyclic fragments.
  • Regression tests are well targeted. One test captures the undercounting bypass; another verifies recursion termination on cyclic fragments. These directly exercise the vulnerable and newly introduced control paths.
  • The release notes clearly document the intended security behavior, which helps downstream maintainers validate whether they need the update.

Cons

  • The patch summary and tests demonstrate correct handling for named fragment spreads, but the provided diff does not show any broader refactor of alias accounting semantics beyond that path. Reviewers should still verify behavior for nested combinations of fields, inline fragments, and repeated fragment reuse under realistic schemas.
  • The cycle handling in MaxAliasesLimiter skips revisiting already-seen fragments rather than surfacing a dedicated validation error itself. In practice this is acceptable because standard GraphQL validation should reject cyclic fragment spreads, and the test expects the standard error message when specified rules are enabled. Still, the limiter's correctness partly relies on the surrounding validation pipeline.
  • The patch fixes counting accuracy for fragment reuse, but it does not by itself solve all GraphQL cost-amplification vectors. Alias count remains only one dimension of query cost.

Verdict

Root-cause.

The supplied patch fixes the core defect described by CVE-2026-47707: alias analysis previously ignored fragment spread expansion, and the new logic explicitly traverses fragment definitions and counts aliases at each use site. The addition of fragment cycle tracking is also the right supporting change, because fragment-aware traversal must be recursion-safe. Based on the provided diff and tests, this is not a superficial threshold adjustment or a narrow signature block; it corrects the analysis model that enabled the bypass.

Engineering recommendation: accept the patch, ship it broadly, and treat it as a security update. Downstream users should still combine alias limits with depth limits and resolver-aware cost controls, but for this CVE specifically, the patch appears complete and technically aligned with the vulnerability description. References: official patch commit, NVD, CVE record.

Sources