From 6ef5dd0d0c6009a97e52f1e1fcec54195ea12ef3 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Fri, 23 Jan 2026 13:05:06 +0300 Subject: [PATCH 01/13] docs(router): Query Complexity --- configs/cargo/Cargo.lock | 2 +- .../content/router/configuration/index.mdx | 2 + .../content/router/configuration/limits.mdx | 143 ++++++++++++++++ .../docs/src/content/router/security/_meta.ts | 1 + .../router/security/query_complexity.mdx | 156 ++++++++++++++++++ 5 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 packages/web/docs/src/content/router/configuration/limits.mdx create mode 100644 packages/web/docs/src/content/router/security/query_complexity.mdx diff --git a/configs/cargo/Cargo.lock b/configs/cargo/Cargo.lock index 2dcc37acf5d..2fb8244fbc2 100644 --- a/configs/cargo/Cargo.lock +++ b/configs/cargo/Cargo.lock @@ -2594,7 +2594,7 @@ dependencies = [ [[package]] name = "hive-apollo-router-plugin" -version = "3.0.0" +version = "3.0.1" dependencies = [ "anyhow", "apollo-router", diff --git a/packages/web/docs/src/content/router/configuration/index.mdx b/packages/web/docs/src/content/router/configuration/index.mdx index 6d0e0b3504e..b953d2c6bee 100644 --- a/packages/web/docs/src/content/router/configuration/index.mdx +++ b/packages/web/docs/src/content/router/configuration/index.mdx @@ -31,3 +31,5 @@ that explains how to use that feature. - [`traffic_shaping`](./configuration/traffic_shaping): Manage connection pooling and request handling to subgraphs. - [`usage_reporting`](./configuration/usage_reporting): Configure usage reporting to Hive Console. +- [`limits`](./configuration/limits): Set limits on query complexity, depth, and other factors to + protect your API. diff --git a/packages/web/docs/src/content/router/configuration/limits.mdx b/packages/web/docs/src/content/router/configuration/limits.mdx new file mode 100644 index 00000000000..3c6e1bea236 --- /dev/null +++ b/packages/web/docs/src/content/router/configuration/limits.mdx @@ -0,0 +1,143 @@ +--- +title: 'limits' +--- + +# limits + +The `limits` configuration allows you to set various limits on incoming GraphQL requests to prevent +too large queries that could lead to overfetching or DOS attacks. + +[Learn more about query complexity and why limiting it is important](../security/query-complexity). + +## Options + +### `max_depth` + +This configures allows you to set a maximum depth for incoming GraphQL queries. Queries that exceed +this depth will be rejected with an error. If not specificied, there is no limit on query depth. + +#### `n` + +- **Type:** `integer` + +The maximum allowed depth for incoming GraphQL queries. + +#### `disable_introspection` + +- **Type:** `boolean` +- **Default:** `false` + +When set to `true`, introspection queries will not be exempt from the depth limit. This means that +introspection queries will also be subject to the maximum depth restriction. This is usually set to +`true` when you want to fully enforce depth limits, including for introspection queries. But be +aware that this may break tools that rely on introspection, because they often generate deep queries +to explore the schema. + +#### `flatten_fragments` + +- **Type:** `boolean` +- **Default:** `false` + +When set to `true`, the depth calculation will consider fragment spreads as if they were inlined. +This provides a more accurate depth measurement, especially when fragments are used extensively in +queries. + +### `max_directives` + +This option allows you to set a maximum number of directives allowed in incoming GraphQL queries. +Queries that exceed this number will be rejected with an error. If not specified, there is no limit +on the number of directives. + +#### `n` + +- **Type:** `integer` + +The maximum allowed number of directives in incoming GraphQL queries. + +### `max_tokens` + +This option allows you to set a maximum number of tokens allowed in incoming GraphQL queries. +Queries that exceed this number will be rejected with an error. If not specified, there is no limit +on the number of tokens. + +#### `n` + +- **Type:** `integer` + +The maximum allowed number of tokens in incoming GraphQL queries. + +## Examples + +### Limit Query Depth to 10 + +```yaml filename="router.config.yaml" +limits: + max_depth: + n: 2 +``` + +In that example, any incoming GraphQL query that exceeds a depth of 2 will be rejected with an +error. + +```graphql +query { + user { + posts { + comments { + text + } + } + } +} +``` + +The above query has a depth of 3 (`user` -> `posts` -> `comments`), so it would be rejected. + +### Limit Directives to 5 + +```yaml filename="router.config.yaml" +limits: + max_directives: + n: 5 +``` + +In that example, any incoming GraphQL query that contains more than 5 directives will be rejected +with an error. + +```graphql +query { + user @include(if: true) { + posts @skip(if: false) { + comments @include(if: true) { + text @skip(if: false) + } + } + } +} +``` + +The above query contains 4 directives, so it would be accepted. If a query contained more than 5 +directives, it would be rejected. + +### Limit Tokens to 10 + +```yaml filename="router.config.yaml" +limits: + max_tokens: + n: 10 +``` + +In that example, any incoming GraphQL query that contains more than 10 tokens will be rejected with +an error. + +```graphql +query { + user { + id + name + } +} +``` + +The above query contains 9 tokens, so it would be accepted. If a query contained more than 10 +tokens, it would be rejected. diff --git a/packages/web/docs/src/content/router/security/_meta.ts b/packages/web/docs/src/content/router/security/_meta.ts index cf4b2a616d1..97ae71e4e1e 100644 --- a/packages/web/docs/src/content/router/security/_meta.ts +++ b/packages/web/docs/src/content/router/security/_meta.ts @@ -3,4 +3,5 @@ export default { cors: 'Configuring CORS', csrf: 'CSRF Prevention', 'jwt-authentication': 'JWT Authentication', + 'query-complexity': 'Query Complexity', }; diff --git a/packages/web/docs/src/content/router/security/query_complexity.mdx b/packages/web/docs/src/content/router/security/query_complexity.mdx new file mode 100644 index 00000000000..ea364dd36e3 --- /dev/null +++ b/packages/web/docs/src/content/router/security/query_complexity.mdx @@ -0,0 +1,156 @@ +--- +title: 'Query Complexity' +--- + +# Query Complexity + +GraphQL by design allows clients to request exactly the data they need. However, this flexibility +can be exploited to create overly complex queries that can strain server resources, leading to +performance degradation or denial of service. To mitigate these risks, it's essential to implement +query complexity limits in your GraphQL router configuration. + +This guide explains how to configure the GraphQL router to enforce query complexity limits to +prevent abusive queries. For the complete configuration options, +[see `limits` in the configuration reference](../configuration/limits). + +## Protection against malicious complex queries + +One of the main benefits of GraphQL is that data can be requested individually. However, this also +introduces the possibility for attackers to send operations with deeply nested selection sets that +could block other requests being processed. Fortunately, infinite loops are not possible by design +as a fragment cannot self-reference itself. Unfortunately, that still does not prevent possible +attackers from sending selection sets that are hundreds of levels deep. + +The following schema: + +```graphql +type Query { + author(id: ID!): Author! +} +type Author { + id: ID! + posts: [Post!]! +} +type Post { + id: ID! + author: Author! +} +``` + +Would allow sending and executing queries such as: + +```graphql +query { + author(id: 42) { + posts { + author { + posts { + author { + posts { + author { + posts { + author { + posts { + author { + posts { + author { + id + } + } + } + } + } + } + } + } + } + } + } + } + } +} +``` + +There are a few ways to mitigate this risk which is covered by this documentation. + +{/* TODO: Persisted Operations */} + +## Reject operations based on the size / tokens + +Parsing a GraphQL operation document is not a cheap operation, but expensive and compute +intensitive. If an attacker sends a very complex operation document with slight variations over and +over again, they can easily degrade the performance of your GraphQL API server. + +Unfortunately because of the possibility of variations, caching parsed documents is not a reliable +way to mitigate this risk. Instead, you can limit the size of incoming operations. + +A potential solution is to limit the maximum number of tokens in a GraphQL document. + +In computer science, lexical analysis, lexing or tokenization is the process of converting a +sequence of characters into a sequence of lexical tokens. + +For example, the given GraphQL operation; + +```graphql +query { + me { + id + user + } +} +``` + +The tokens are `query`, `{`, `me`, `{`, `id`, `user`, `}`, `}` which gives a total of 8 tokens. + +The optimal maximum token count for your application depends on the complexity of the GraphQL +operations and documents. Usually 800-2000 tokens seems like a sane default. + +You can use tools like +[GraphQL Inspector](https://the-guild.dev/graphql/inspector/docs/essentials/audit) to analyse and +find the best defaults for your use cases. + +But on the API side, you can configure the maximum amount of like below; + +```yaml filename="router.config.yaml" +limits: + max_tokens: + n: 1000 +``` + +In that example, any incoming GraphQL query that exceeds 1000 tokens will be rejected with an error. + +## Prevent deeply nested queries + +Sometimes you cannot use persisted operations, and you build an API that is available to the 3rd +party users. In that case, it is recommended to limit the maximum depth of incoming GraphQL queries +to prevent overly complex queries. + +```yaml filename="router.config.yaml" +limits: + max_depth: + n: 10 +``` + +In that example, any incoming GraphQL query that exceeds a depth of 10 will be rejected with an +error. + +```graphql +query { + user { + posts { + comments { + text + } + } + } +} +``` + +The above query has a depth of 3 (`user` -> `posts` -> `comments`), so it would be accepted. If a +query exceeded a depth of 10, it would be rejected. + +This can prevent malicious API users executing GraphQL operations with deeply nested selection sets. +You need to tweak the maximum depth an operation selection set is allowed to have based on your +schema and needs, as it could vary between users. + +{/* TODO: Rate Limiting here */} From 885e1cd06f873ec6eb53825d7c5cad1f72cfbda7 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Fri, 23 Jan 2026 13:07:26 +0300 Subject: [PATCH 02/13] .. --- .../docs/src/content/router/security/query_complexity.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/web/docs/src/content/router/security/query_complexity.mdx b/packages/web/docs/src/content/router/security/query_complexity.mdx index ea364dd36e3..01820a0dd01 100644 --- a/packages/web/docs/src/content/router/security/query_complexity.mdx +++ b/packages/web/docs/src/content/router/security/query_complexity.mdx @@ -17,9 +17,9 @@ prevent abusive queries. For the complete configuration options, One of the main benefits of GraphQL is that data can be requested individually. However, this also introduces the possibility for attackers to send operations with deeply nested selection sets that -could block other requests being processed. Fortunately, infinite loops are not possible by design -as a fragment cannot self-reference itself. Unfortunately, that still does not prevent possible -attackers from sending selection sets that are hundreds of levels deep. +could block other requests being processed. Even if infinite loops are not possible by design as a +fragment cannot self-reference itself; but that still does not prevent possible attackers from +sending selection sets that are hundreds of levels deep. The following schema: From 253effff4a6da1662d32e4c50fdf7f61fadb1d2e Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Fri, 23 Jan 2026 13:07:48 +0300 Subject: [PATCH 03/13] .. --- .../docs/src/content/router/security/query_complexity.mdx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/web/docs/src/content/router/security/query_complexity.mdx b/packages/web/docs/src/content/router/security/query_complexity.mdx index 01820a0dd01..235d56d7980 100644 --- a/packages/web/docs/src/content/router/security/query_complexity.mdx +++ b/packages/web/docs/src/content/router/security/query_complexity.mdx @@ -121,9 +121,8 @@ In that example, any incoming GraphQL query that exceeds 1000 tokens will be rej ## Prevent deeply nested queries -Sometimes you cannot use persisted operations, and you build an API that is available to the 3rd -party users. In that case, it is recommended to limit the maximum depth of incoming GraphQL queries -to prevent overly complex queries. +If you build an API that is available to the 3rd party users, it is recommended to limit the maximum +depth of incoming GraphQL queries to prevent overly complex queries. ```yaml filename="router.config.yaml" limits: From 0bc2b815931849495fd0a5f692c3f4193e0c22a0 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Fri, 23 Jan 2026 13:12:40 +0300 Subject: [PATCH 04/13] .. --- .../router/security/query_complexity.mdx | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/packages/web/docs/src/content/router/security/query_complexity.mdx b/packages/web/docs/src/content/router/security/query_complexity.mdx index 235d56d7980..93472eabeaf 100644 --- a/packages/web/docs/src/content/router/security/query_complexity.mdx +++ b/packages/web/docs/src/content/router/security/query_complexity.mdx @@ -153,3 +153,58 @@ You need to tweak the maximum depth an operation selection set is allowed to hav schema and needs, as it could vary between users. {/* TODO: Rate Limiting here */} + +## Why both `max_depth` and `max_tokens`? + +Both `max_depth` and `max_tokens` serve different purposes in protecting your GraphQL API from +abusive queries. + +- `max_depth` specifically targets the structure of the query, preventing excessively nested + selection sets that can lead to performance issues. This is particularly important in GraphQL, + where deeply nested queries can be constructed even without a large number of tokens. +- `max_tokens`, on the other hand, provides a broader safeguard by limiting the overall size of the + query. This helps to prevent attacks that exploit the complexity of queries through a large number + of fields, arguments, and other GraphQL constructs, regardless of their nesting level. + +The following operation has 20 tokens and a depth of 5 which will be rejected by both limits if set +to 10 and 15 respectively: + +```graphql +query { + author(id: 1) { + id + posts { + id + author { + id + posts { + id + } + } + } + } +} +``` + +So you might think `max_depth` is sufficient enough, however consider the below operation. The +following operation has 20 tokens but only a depth of 2: + +```graphql +query { + me { + id + name + email + } + post(id: 1) { + id + title + content + } +} +``` + +This operation passes a `max_depth` of 2 but would be rejected by a `max_tokens` limit of 10. + +By implementing both `max_depth` and `max_tokens`, you create a more robust defense against a wider +range of potential query abuses, ensuring better performance and reliability for your GraphQL API. From 11ca12e34de8863c3969ba79c1378a8ff879aa85 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Fri, 23 Jan 2026 13:16:10 +0300 Subject: [PATCH 05/13] Fixese --- .../docs/src/content/router/configuration/limits.mdx | 9 +++++---- .../src/content/router/security/query_complexity.mdx | 10 +++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/web/docs/src/content/router/configuration/limits.mdx b/packages/web/docs/src/content/router/configuration/limits.mdx index 3c6e1bea236..15f2890236f 100644 --- a/packages/web/docs/src/content/router/configuration/limits.mdx +++ b/packages/web/docs/src/content/router/configuration/limits.mdx @@ -13,8 +13,9 @@ too large queries that could lead to overfetching or DOS attacks. ### `max_depth` -This configures allows you to set a maximum depth for incoming GraphQL queries. Queries that exceed -this depth will be rejected with an error. If not specificied, there is no limit on query depth. +This configuration allows you to set a maximum depth for incoming GraphQL queries. Queries that +exceed this depth will be rejected with an error. If not specified, there is no limit on query +depth. #### `n` @@ -68,7 +69,7 @@ The maximum allowed number of tokens in incoming GraphQL queries. ## Examples -### Limit Query Depth to 10 +### Limit Query Depth to 2 ```yaml filename="router.config.yaml" limits: @@ -139,5 +140,5 @@ query { } ``` -The above query contains 9 tokens, so it would be accepted. If a query contained more than 10 +The above query contains 8 tokens, so it would be accepted. If a query contained more than 10 tokens, it would be rejected. diff --git a/packages/web/docs/src/content/router/security/query_complexity.mdx b/packages/web/docs/src/content/router/security/query_complexity.mdx index 93472eabeaf..150db61b18d 100644 --- a/packages/web/docs/src/content/router/security/query_complexity.mdx +++ b/packages/web/docs/src/content/router/security/query_complexity.mdx @@ -77,9 +77,9 @@ There are a few ways to mitigate this risk which is covered by this documentatio ## Reject operations based on the size / tokens -Parsing a GraphQL operation document is not a cheap operation, but expensive and compute -intensitive. If an attacker sends a very complex operation document with slight variations over and -over again, they can easily degrade the performance of your GraphQL API server. +Parsing a GraphQL operation document is not a cheap operation, but expensive and compute-intensive. +If an attacker sends a very complex operation document with slight variations over and over again, +they can easily degrade the performance of your GraphQL API server. Unfortunately because of the possibility of variations, caching parsed documents is not a reliable way to mitigate this risk. Instead, you can limit the size of incoming operations. @@ -109,7 +109,7 @@ You can use tools like [GraphQL Inspector](https://the-guild.dev/graphql/inspector/docs/essentials/audit) to analyse and find the best defaults for your use cases. -But on the API side, you can configure the maximum amount of like below; +But on the API side, you can configure the maximum amount as shown below; ```yaml filename="router.config.yaml" limits: @@ -121,7 +121,7 @@ In that example, any incoming GraphQL query that exceeds 1000 tokens will be rej ## Prevent deeply nested queries -If you build an API that is available to the 3rd party users, it is recommended to limit the maximum +If you build an API that is available to the 3rd-party users, it is recommended to limit the maximum depth of incoming GraphQL queries to prevent overly complex queries. ```yaml filename="router.config.yaml" From a80634c7419735f0c2d62968a408a2b64a5eebc4 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Fri, 23 Jan 2026 13:24:06 +0300 Subject: [PATCH 06/13] .. --- packages/web/docs/src/content/router/security/_meta.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/docs/src/content/router/security/_meta.ts b/packages/web/docs/src/content/router/security/_meta.ts index 97ae71e4e1e..7bfa96c0523 100644 --- a/packages/web/docs/src/content/router/security/_meta.ts +++ b/packages/web/docs/src/content/router/security/_meta.ts @@ -3,5 +3,5 @@ export default { cors: 'Configuring CORS', csrf: 'CSRF Prevention', 'jwt-authentication': 'JWT Authentication', - 'query-complexity': 'Query Complexity', + query_complexity: 'Query Complexity', }; From f938a9bf02e0a6797b706a33d27661a59944541d Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 26 Jan 2026 12:18:03 +0300 Subject: [PATCH 07/13] Operation complexity --- .../docs/src/content/router/security/_meta.ts | 2 +- ...omplexity.mdx => operation_complexity.mdx} | 64 +++++++++++-------- 2 files changed, 37 insertions(+), 29 deletions(-) rename packages/web/docs/src/content/router/security/{query_complexity.mdx => operation_complexity.mdx} (62%) diff --git a/packages/web/docs/src/content/router/security/_meta.ts b/packages/web/docs/src/content/router/security/_meta.ts index 7bfa96c0523..23ef8874b30 100644 --- a/packages/web/docs/src/content/router/security/_meta.ts +++ b/packages/web/docs/src/content/router/security/_meta.ts @@ -3,5 +3,5 @@ export default { cors: 'Configuring CORS', csrf: 'CSRF Prevention', 'jwt-authentication': 'JWT Authentication', - query_complexity: 'Query Complexity', + operation_complexity: 'Operation Complexity', }; diff --git a/packages/web/docs/src/content/router/security/query_complexity.mdx b/packages/web/docs/src/content/router/security/operation_complexity.mdx similarity index 62% rename from packages/web/docs/src/content/router/security/query_complexity.mdx rename to packages/web/docs/src/content/router/security/operation_complexity.mdx index 150db61b18d..2fb91ee75b4 100644 --- a/packages/web/docs/src/content/router/security/query_complexity.mdx +++ b/packages/web/docs/src/content/router/security/operation_complexity.mdx @@ -1,19 +1,19 @@ --- -title: 'Query Complexity' +title: 'Operation Complexity' --- -# Query Complexity +# Operation Complexity GraphQL by design allows clients to request exactly the data they need. However, this flexibility -can be exploited to create overly complex queries that can strain server resources, leading to -performance degradation or denial of service. To mitigate these risks, it's essential to implement -query complexity limits in your GraphQL router configuration. +can be exploited to create overly complex GraphQL operations that can strain server resources, +leading to performance degradation or denial of service. To mitigate these risks, it's essential to +implement operation complexity limits in your GraphQL router configuration. -This guide explains how to configure the GraphQL router to enforce query complexity limits to -prevent abusive queries. For the complete configuration options, +This guide explains how to configure the GraphQL router to enforce operation complexity limits to +prevent abusive GraphQL operations. For the complete configuration options, [see `limits` in the configuration reference](../configuration/limits). -## Protection against malicious complex queries +## Protection against malicious complex GraphQL operations One of the main benefits of GraphQL is that data can be requested individually. However, this also introduces the possibility for attackers to send operations with deeply nested selection sets that @@ -37,7 +37,7 @@ type Post { } ``` -Would allow sending and executing queries such as: +Would allow sending and executing GraphQL operations such as: ```graphql query { @@ -77,12 +77,16 @@ There are a few ways to mitigate this risk which is covered by this documentatio ## Reject operations based on the size / tokens -Parsing a GraphQL operation document is not a cheap operation, but expensive and compute-intensive. -If an attacker sends a very complex operation document with slight variations over and over again, -they can easily degrade the performance of your GraphQL API server. +Parsing a GraphQL operation is not a cheap process, but an expensive and compute-intensive one. In +order to avoid to parse the operations over and over again, Hive Router has a built-in parsing cache +that stores the parsed documents by their string representation. -Unfortunately because of the possibility of variations, caching parsed documents is not a reliable -way to mitigate this risk. Instead, you can limit the size of incoming operations. +However, due to the flexibility of GraphQL, an attacker could send a very complex operation document +with slight variations over and over again, which would bypass the parsing cache and degrade the +performance of your GraphQL API server. + +In that case, parsing cache by itself is not sufficient to protect your API server from abusive +GraphQL operations. In addition to the caching, you can limit the size of incoming operations. A potential solution is to limit the maximum number of tokens in a GraphQL document. @@ -103,7 +107,7 @@ query { The tokens are `query`, `{`, `me`, `{`, `id`, `user`, `}`, `}` which gives a total of 8 tokens. The optimal maximum token count for your application depends on the complexity of the GraphQL -operations and documents. Usually 800-2000 tokens seems like a sane default. +operations and documents. You can use tools like [GraphQL Inspector](https://the-guild.dev/graphql/inspector/docs/essentials/audit) to analyse and @@ -117,12 +121,14 @@ limits: n: 1000 ``` -In that example, any incoming GraphQL query that exceeds 1000 tokens will be rejected with an error. +In that example, any incoming GraphQL operation that exceeds 1000 tokens will be rejected with an +error. -## Prevent deeply nested queries +## Prevent deeply nested GraphQL operations -If you build an API that is available to the 3rd-party users, it is recommended to limit the maximum -depth of incoming GraphQL queries to prevent overly complex queries. +If you build an API that is open which means it is accessible by the public or 3rd-party consumers, +it is recommended to limit the maximum depth of incoming GraphQL operations to prevent overly +complex GraphQL operations. ```yaml filename="router.config.yaml" limits: @@ -130,7 +136,7 @@ limits: n: 10 ``` -In that example, any incoming GraphQL query that exceeds a depth of 10 will be rejected with an +In that example, any incoming GraphQL operation that exceeds a depth of 10 will be rejected with an error. ```graphql @@ -145,8 +151,8 @@ query { } ``` -The above query has a depth of 3 (`user` -> `posts` -> `comments`), so it would be accepted. If a -query exceeded a depth of 10, it would be rejected. +The above operation has a depth of 3 (`user` -> `posts` -> `comments`), so it would be accepted. If +an operation exceeded a depth of 10, it would be rejected. This can prevent malicious API users executing GraphQL operations with deeply nested selection sets. You need to tweak the maximum depth an operation selection set is allowed to have based on your @@ -157,14 +163,15 @@ schema and needs, as it could vary between users. ## Why both `max_depth` and `max_tokens`? Both `max_depth` and `max_tokens` serve different purposes in protecting your GraphQL API from -abusive queries. +abusive GraphQL operations. -- `max_depth` specifically targets the structure of the query, preventing excessively nested +- `max_depth` specifically targets the structure of the operation, preventing excessively nested selection sets that can lead to performance issues. This is particularly important in GraphQL, - where deeply nested queries can be constructed even without a large number of tokens. + where deeply nested GraphQL operations can be constructed even without a large number of tokens. - `max_tokens`, on the other hand, provides a broader safeguard by limiting the overall size of the - query. This helps to prevent attacks that exploit the complexity of queries through a large number - of fields, arguments, and other GraphQL constructs, regardless of their nesting level. + operation. This helps to prevent attacks that exploit the complexity of GraphQL operations through + a large number of fields, arguments, and other GraphQL constructs, regardless of their nesting + level. The following operation has 20 tokens and a depth of 5 which will be rejected by both limits if set to 10 and 15 respectively: @@ -207,4 +214,5 @@ query { This operation passes a `max_depth` of 2 but would be rejected by a `max_tokens` limit of 10. By implementing both `max_depth` and `max_tokens`, you create a more robust defense against a wider -range of potential query abuses, ensuring better performance and reliability for your GraphQL API. +range of potential operation abuses, ensuring better performance and reliability for your GraphQL +API. From 5563fa1bfdd7a3ed7329d4e0b45342884d7239b3 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 26 Jan 2026 12:18:39 +0300 Subject: [PATCH 08/13] Removed --- .../docs/src/content/router/security/operation_complexity.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/web/docs/src/content/router/security/operation_complexity.mdx b/packages/web/docs/src/content/router/security/operation_complexity.mdx index 2fb91ee75b4..d04eec8a37e 100644 --- a/packages/web/docs/src/content/router/security/operation_complexity.mdx +++ b/packages/web/docs/src/content/router/security/operation_complexity.mdx @@ -151,8 +151,7 @@ query { } ``` -The above operation has a depth of 3 (`user` -> `posts` -> `comments`), so it would be accepted. If -an operation exceeded a depth of 10, it would be rejected. +The above operation has a depth of 3 (`user` -> `posts` -> `comments`), so it would be accepted. This can prevent malicious API users executing GraphQL operations with deeply nested selection sets. You need to tweak the maximum depth an operation selection set is allowed to have based on your From 8d119a9e1411e23175be626148103a1f53184dac Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 26 Jan 2026 12:19:40 +0300 Subject: [PATCH 09/13] renamed --- .../docs/src/content/router/security/operation_complexity.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/docs/src/content/router/security/operation_complexity.mdx b/packages/web/docs/src/content/router/security/operation_complexity.mdx index d04eec8a37e..905ab5bd40b 100644 --- a/packages/web/docs/src/content/router/security/operation_complexity.mdx +++ b/packages/web/docs/src/content/router/security/operation_complexity.mdx @@ -159,7 +159,7 @@ schema and needs, as it could vary between users. {/* TODO: Rate Limiting here */} -## Why both `max_depth` and `max_tokens`? +## Why using `max_depth` along with `max_tokens` Both `max_depth` and `max_tokens` serve different purposes in protecting your GraphQL API from abusive GraphQL operations. From 03f904633c7b97078272a0fb0dac00616f48e418 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 26 Jan 2026 12:21:44 +0300 Subject: [PATCH 10/13] Router --- .../docs/src/content/router/security/operation_complexity.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/docs/src/content/router/security/operation_complexity.mdx b/packages/web/docs/src/content/router/security/operation_complexity.mdx index 905ab5bd40b..a1602473814 100644 --- a/packages/web/docs/src/content/router/security/operation_complexity.mdx +++ b/packages/web/docs/src/content/router/security/operation_complexity.mdx @@ -83,7 +83,7 @@ that stores the parsed documents by their string representation. However, due to the flexibility of GraphQL, an attacker could send a very complex operation document with slight variations over and over again, which would bypass the parsing cache and degrade the -performance of your GraphQL API server. +performance of your GraphQL router. In that case, parsing cache by itself is not sufficient to protect your API server from abusive GraphQL operations. In addition to the caching, you can limit the size of incoming operations. From 1e3708aac9f2d4a1ebba14b28bd9f0942a7ab0ee Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 26 Jan 2026 12:22:18 +0300 Subject: [PATCH 11/13] ... --- .../docs/src/content/router/security/operation_complexity.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/web/docs/src/content/router/security/operation_complexity.mdx b/packages/web/docs/src/content/router/security/operation_complexity.mdx index a1602473814..135b1613fde 100644 --- a/packages/web/docs/src/content/router/security/operation_complexity.mdx +++ b/packages/web/docs/src/content/router/security/operation_complexity.mdx @@ -7,7 +7,8 @@ title: 'Operation Complexity' GraphQL by design allows clients to request exactly the data they need. However, this flexibility can be exploited to create overly complex GraphQL operations that can strain server resources, leading to performance degradation or denial of service. To mitigate these risks, it's essential to -implement operation complexity limits in your GraphQL router configuration. +implement operation complexity limits in your GraphQL router configuration, especially in production +environments. This guide explains how to configure the GraphQL router to enforce operation complexity limits to prevent abusive GraphQL operations. For the complete configuration options, From bcbab4647802b718bccbc3363f498e572d9dd14b Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Mon, 26 Jan 2026 14:02:20 +0300 Subject: [PATCH 12/13] Update --- packages/web/docs/src/content/router/configuration/index.mdx | 2 +- packages/web/docs/src/content/router/configuration/limits.mdx | 2 +- packages/web/docs/src/content/router/security/_meta.ts | 2 +- .../{operation_complexity.mdx => operation-cost-analysis.mdx} | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) rename packages/web/docs/src/content/router/security/{operation_complexity.mdx => operation-cost-analysis.mdx} (99%) diff --git a/packages/web/docs/src/content/router/configuration/index.mdx b/packages/web/docs/src/content/router/configuration/index.mdx index b953d2c6bee..aa8c45333c3 100644 --- a/packages/web/docs/src/content/router/configuration/index.mdx +++ b/packages/web/docs/src/content/router/configuration/index.mdx @@ -31,5 +31,5 @@ that explains how to use that feature. - [`traffic_shaping`](./configuration/traffic_shaping): Manage connection pooling and request handling to subgraphs. - [`usage_reporting`](./configuration/usage_reporting): Configure usage reporting to Hive Console. -- [`limits`](./configuration/limits): Set limits on query complexity, depth, and other factors to +- [`limits`](./configuration/limits): Set limits on operation cost, depth, and other factors to protect your API. diff --git a/packages/web/docs/src/content/router/configuration/limits.mdx b/packages/web/docs/src/content/router/configuration/limits.mdx index 15f2890236f..7a19f3e2684 100644 --- a/packages/web/docs/src/content/router/configuration/limits.mdx +++ b/packages/web/docs/src/content/router/configuration/limits.mdx @@ -7,7 +7,7 @@ title: 'limits' The `limits` configuration allows you to set various limits on incoming GraphQL requests to prevent too large queries that could lead to overfetching or DOS attacks. -[Learn more about query complexity and why limiting it is important](../security/query-complexity). +[Learn more about operation cost analysis and why limiting it is important](../security/operation-cost-analysis). ## Options diff --git a/packages/web/docs/src/content/router/security/_meta.ts b/packages/web/docs/src/content/router/security/_meta.ts index 23ef8874b30..8a82312a619 100644 --- a/packages/web/docs/src/content/router/security/_meta.ts +++ b/packages/web/docs/src/content/router/security/_meta.ts @@ -3,5 +3,5 @@ export default { cors: 'Configuring CORS', csrf: 'CSRF Prevention', 'jwt-authentication': 'JWT Authentication', - operation_complexity: 'Operation Complexity', + 'operation-cost-analysis': 'Operation Cost Analysis', }; diff --git a/packages/web/docs/src/content/router/security/operation_complexity.mdx b/packages/web/docs/src/content/router/security/operation-cost-analysis.mdx similarity index 99% rename from packages/web/docs/src/content/router/security/operation_complexity.mdx rename to packages/web/docs/src/content/router/security/operation-cost-analysis.mdx index 135b1613fde..8e712977020 100644 --- a/packages/web/docs/src/content/router/security/operation_complexity.mdx +++ b/packages/web/docs/src/content/router/security/operation-cost-analysis.mdx @@ -1,8 +1,8 @@ --- -title: 'Operation Complexity' +title: 'Operation Cost Analysis' --- -# Operation Complexity +# Operation Cost Analysis GraphQL by design allows clients to request exactly the data they need. However, this flexibility can be exploited to create overly complex GraphQL operations that can strain server resources, From bf39d7d5d08520256c2d7335285df86e3d3824fe Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Tue, 27 Jan 2026 16:03:01 +0300 Subject: [PATCH 13/13] Back to Operation Complexity --- packages/web/docs/src/content/router/configuration/limits.mdx | 2 +- packages/web/docs/src/content/router/security/_meta.ts | 2 +- .../{operation-cost-analysis.mdx => operation-complexity.mdx} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename packages/web/docs/src/content/router/security/{operation-cost-analysis.mdx => operation-complexity.mdx} (99%) diff --git a/packages/web/docs/src/content/router/configuration/limits.mdx b/packages/web/docs/src/content/router/configuration/limits.mdx index 7a19f3e2684..d2ab68f2a17 100644 --- a/packages/web/docs/src/content/router/configuration/limits.mdx +++ b/packages/web/docs/src/content/router/configuration/limits.mdx @@ -7,7 +7,7 @@ title: 'limits' The `limits` configuration allows you to set various limits on incoming GraphQL requests to prevent too large queries that could lead to overfetching or DOS attacks. -[Learn more about operation cost analysis and why limiting it is important](../security/operation-cost-analysis). +[Learn more about operation complexity and why limiting it is important](../security/operation-complexity). ## Options diff --git a/packages/web/docs/src/content/router/security/_meta.ts b/packages/web/docs/src/content/router/security/_meta.ts index 8a82312a619..e3ece580b18 100644 --- a/packages/web/docs/src/content/router/security/_meta.ts +++ b/packages/web/docs/src/content/router/security/_meta.ts @@ -3,5 +3,5 @@ export default { cors: 'Configuring CORS', csrf: 'CSRF Prevention', 'jwt-authentication': 'JWT Authentication', - 'operation-cost-analysis': 'Operation Cost Analysis', + 'operation-complexity': 'Operation Complexity', }; diff --git a/packages/web/docs/src/content/router/security/operation-cost-analysis.mdx b/packages/web/docs/src/content/router/security/operation-complexity.mdx similarity index 99% rename from packages/web/docs/src/content/router/security/operation-cost-analysis.mdx rename to packages/web/docs/src/content/router/security/operation-complexity.mdx index 8e712977020..135b1613fde 100644 --- a/packages/web/docs/src/content/router/security/operation-cost-analysis.mdx +++ b/packages/web/docs/src/content/router/security/operation-complexity.mdx @@ -1,8 +1,8 @@ --- -title: 'Operation Cost Analysis' +title: 'Operation Complexity' --- -# Operation Cost Analysis +# Operation Complexity GraphQL by design allows clients to request exactly the data they need. However, this flexibility can be exploited to create overly complex GraphQL operations that can strain server resources,