How do field aliases let one GraphQL document request the same field hundreds of times?
answer
- One document, many response keys
- Renaming decides what groups together
- Grouping happens by key, not by name
- Width, not nesting depth
- Merging rule permits it, never collapses it
basics
~20 sAn alias sets the key a field's value appears under in the response, so the same field can be selected many times under different keys. Each aliased selection is executed separately, multiplying the server's work.
solid answer
~50 sIn an executable document a selected field's **response key** is its alias when it has one and its field name otherwise. Selections are grouped by response key, and each group is resolved once. Two selections under *different* aliases are different keys, so they are executed separately even when they name the identical field with identical arguments. Nothing in GraphQL caps how many aliases a selection set may carry, so a three-kilobyte document can select the most expensive field in a schema under 247 aliases and cause 247 executions. The validation rule that fields be mergeable applies only to selections sharing a response key, so it never fires here. This is amplification by *width*, which a depth limit, a body-size cap and an HTTP request rate limit all fail to see; static cost scoring and per-field occurrence counts do see it, because they count response keys.
code
graphql · 5 linesquery MemoryScan($locale: Locale!) {
a1: match(source: "quarterly settlement notice", locale: $locale, first: 8400) { segmentId score }
a2: match(source: "quarterly settlement notice", locale: $locale, first: 8400) { segmentId score }
a3: match(source: "quarterly settlement notice", locale: $locale, first: 8400) { segmentId score }
}go deeper
Recall that an alias sets the response key, and that two different keys mean the same field runs twice. Be able to write a short document that selects one field three times and describe the response shape it produces.
Explain the mechanics: fields are collected and grouped by response key, one execution per group, and the mergeability rule applies only within a group. Then show why byte-size and depth are the wrong things to measure.
Demonstrate that you would count response keys rather than requests, and say which existing controls silently miss this — proxy rate limits, response caches keyed on document text, per-request logging — and what a realistic occurrence cap looks like on your hottest field.
Own the framing that on a single-endpoint protocol every per-request budget is divided by document width, and decide where the accounting unit lives across the fleet so that limits, metrics and billing all agree on what one unit of work is.
## A field's key in the response is its alias, not its name When a server executes a document it does not build the response map from field *names*. It builds it from **response keys**. A selected field's response key is its alias when it carries one, and its field name when it does not. Everything about repetition follows from that single rule. Field collection walks a selection set and groups selections **by response key**. Every group becomes exactly one entry in the response map, and each group is resolved once — the selections inside a group have their sub-selection sets merged and the field is executed a single time. That is why `translator { id } translator { name }` costs one resolution of `translator` and produces one `translator` object carrying both keys. Give two selections different aliases and they land in *different* groups. They are two entries in the response map, so they are two executions — even when the aliases name the identical field with byte-identical arguments. Nothing merges them, because merging is defined per response key and these keys differ. ## The validation rule people expect to save them does not Documents are checked by a rule requiring that any two selections sharing a response key be *mergeable*: they must name the same field with the same arguments, and their sub-selections must themselves merge. The rule exists so a single response key can never have two conflicting meanings. It is a **consistency** rule, not a **deduplication** rule, and it never fires on distinct aliases, because distinct aliases are exactly the case the rule was written to permit. A document with 247 aliases over one field is not merely accepted — it is unambiguously valid, and a server that quietly collapsed those selections would be violating the response-shape guarantee that the client relies on. ## Why aliases exist at all This is not an oversight. Aliases are the only way a client can ask one question twice with different arguments and get both answers back distinguishably: two locales of the same lookup, this month's and last month's slice, an object fetched by two different identifiers. A response map keyed by field name could express only one of each. The feature and the abuse are the same mechanism. ## The arithmetic Consider a translation-memory graph whose `match(source:, locale:, first:)` field runs a fuzzy similarity search across a segment corpus — the single most expensive field in the schema. One caller sends a document under three kilobytes that selects `match(source: "quarterly settlement notice", locale: DE_DE, first: 8400)` under 247 aliases. The parse is trivial. The document passes every structural rule. Execution then performs 247 similarity searches and completes 2,074,800 rows of result — from one HTTP request, one JSON body, one entry in the access log. Amplification of this kind is *width*, and width is invisible to most of the controls people reach for first: - A **depth limit** counts nesting. The malicious document is two levels deep; a hand-written product document is often deeper. - A **body-size cap** counts bytes. Aliases are cheap to write — `a1:`, `a2:` — so the ratio of bytes sent to work caused is enormous. - An **HTTP rate limit**, whether at a reverse proxy, a CDN or the application edge, counts requests. This is one request. - A **normalized client cache** or a server response cache keyed by document text sees a document it has never seen before, so nothing is served from cache. ## What does see it The controls that notice are the ones that count *selections* rather than requests. Static cost scoring walks the collected fields and scores every response key separately, so 247 aliased `match` selections score 247 times the weight of one — and if a list-slice argument such as `first` is used as a multiplier, the score reflects the 8,400 too. A field-occurrence cap counts how many times a named field appears in a document. Both run before execution, on the document alone, which is what makes them affordable. Complementing them, per-request backend batching bounds how many *database* calls those resolutions turn into, but it does not bound the similarity searches themselves — deduplication only helps when the repeated selections are genuinely identical, and an attacker who varies one argument per alias defeats it while keeping the amplification. ## What to say in an interview Say that the response key is the unit of execution, that aliases mint new response keys, and that therefore the number of times a field runs is bounded by the document's *width*, which nothing in GraphQL bounds by default. Then name the counting unit you would enforce on: occurrences of a field per document, not requests per client. That answer shows you understand why a perfectly ordinary rate limit reports a quiet endpoint while the database is on fire.
- Why does the validation rule requiring selections to be mergeable not collapse the repeated selections?That rule only constrains selections that share a response key: it forbids one key from meaning two different things. Distinct aliases are distinct keys, so the rule is satisfied trivially and has nothing to merge. It is a consistency rule, not a deduplication rule.
- Does it change anything if the attacker varies one argument per alias?It makes the amplification harder to defend against. Identical selections can at least be deduplicated by a per-request batch cache or a response cache; varying a locale, a search string or a slice size per alias defeats that while keeping the multiplication. Cost scoring still counts each key, so a document-level score remains the control that holds.
- Which controls miss alias amplification entirely?Anything counting the wrong unit: a nesting-depth limit sees two levels, a body-size cap sees a few kilobytes, and an HTTP rate limit at a reverse proxy or CDN sees one request. Counting response keys — occurrences of a field per document, or a static cost per key — is what catches it.
It is the difference between asking a librarian for one book and handing over 247 request slips that all name the same book — the slips are cheap to write, and each one still sends someone into the stacks.
saying these in an interview costs you the question
- Aliases are cosmetic renaming with no execution cost
- The server automatically merges identical field selections
- A nesting-depth limit stops alias amplification
- A per-request rate limit counts each aliased selection
- Validation rejects a field selected many times
- Aliases are only usable on query operations