GHSA-HMFR-RX46-4JX2
Vulnerability from github – Published: 2025-08-26 18:42 – Updated: 2025-08-26 18:42Summary
A query depth restriction using the max-depth property can be bypassed if ignoreIntrospection is enabled (which is the default configuration) by naming your query/fragment __schema.
Details
At the start of the countDepth function, we have the following check for the ignoreIntrospection option:
if (this.config.ignoreIntrospection && 'name' in node && node.name?.value === '__schema') {
return 0;
}
However, the node can be one of: FieldNode, FragmentDefinitionNode, InlineFragmentNode, OperationDefinitionNode, FragmentSpreadNode.
For example, consider sending the following query:
query hello {
books {
title
}
}
This would create an OperationDefinitionNode where node.name.value == 'hello'
The proper way to handle this is to check explicitly for the __schema field, which corresponds to a FieldNode.
The fix is
if (
this.config.ignoreIntrospection &&
'name' in node &&
node.name?.value === '__schema' &&
node.kind === Kind.FIELD
) {
return 0;
}
This ensures that the node is explicitly a FieldNode.
PoC
Max depth: 6
query {
books {
author {
books {
author {
...__schema
}
}
}
}
}
fragment __schema on Author {
books {
title
}
}
Impact
This issue affects applications using the GraphQL Armor Depth Limit plugin with ignoreIntrospection enabled.
Fix
This is fixed in PR#823
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.4.1"
},
"package": {
"ecosystem": "npm",
"name": "@escape.tech/graphql-armor-max-depth"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.4.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-400"
],
"github_reviewed": true,
"github_reviewed_at": "2025-08-26T18:42:37Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\nA query depth restriction using the `max-depth` property can be bypassed if `ignoreIntrospection` is enabled (which is the default configuration) by naming your query/fragment `__schema`.\n\n### Details\nAt the start of the `countDepth` function, we have the following check for the `ignoreIntrospection` option:\n\n```typescript\n if (this.config.ignoreIntrospection \u0026\u0026 \u0027name\u0027 in node \u0026\u0026 node.name?.value === \u0027__schema\u0027) {\n return 0;\n }\n```\n\nHowever, the `node` can be one of: `FieldNode`, `FragmentDefinitionNode`, `InlineFragmentNode`, `OperationDefinitionNode`, `FragmentSpreadNode`.\n\nFor example, consider sending the following query:\n\n```graphql\nquery hello {\n books {\n title\n }\n}\n```\n\nThis would create an `OperationDefinitionNode` where `node.name.value == \u0027hello\u0027`\n\nThe proper way to handle this is to check explicitly for the `__schema` field, which corresponds to a `FieldNode`.\n\nThe fix is\n\n```typescript\n if (\n this.config.ignoreIntrospection \u0026\u0026\n \u0027name\u0027 in node \u0026\u0026\n node.name?.value === \u0027__schema\u0027 \u0026\u0026\n node.kind === Kind.FIELD\n ) {\n return 0;\n }\n```\n\nThis ensures that the node is explicitly a `FieldNode`.\n\n### PoC\n\nMax depth: `6`\n\n```graphql\nquery {\n books {\n author {\n books {\n author {\n ...__schema\n }\n }\n }\n }\n}\nfragment __schema on Author {\n books {\n title\n }\n}\n```\n\n### Impact\n\nThis issue affects applications using the GraphQL Armor Depth Limit plugin with `ignoreIntrospection` enabled.\n\n### Fix\n\nThis is fixed in [PR#823](https://github.com/Escape-Technologies/graphql-armor/pull/823)",
"id": "GHSA-hmfr-rx46-4jx2",
"modified": "2025-08-26T18:42:37Z",
"published": "2025-08-26T18:42:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/Escape-Technologies/graphql-armor/security/advisories/GHSA-hmfr-rx46-4jx2"
},
{
"type": "WEB",
"url": "https://github.com/Escape-Technologies/graphql-armor/pull/823"
},
{
"type": "WEB",
"url": "https://github.com/Escape-Technologies/graphql-armor/commit/1f923bc09f5f053f60b6ba2bd419d4b94cbe1db3"
},
{
"type": "PACKAGE",
"url": "https://github.com/Escape-Technologies/graphql-armor"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "GraphQL Armor Max-Depth Plugin Bypass via Introspection Query Obfuscation"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.