Headline
GHSA-hmfr-rx46-4jx2: GraphQL Armor Max-Depth Plugin Bypass via Introspection Query Obfuscation
Summary
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
Summary
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
References
- GHSA-hmfr-rx46-4jx2
- Escape-Technologies/graphql-armor#823
- Escape-Technologies/graphql-armor@1f923bc