Skip to content

Commit 1462c91

Browse files
Add non-local and recursive selection limits (#3238)
Certain query patterns may cause resource exhaustion. Corrects a set of denial-of-service (DOS) vulnerabilities that made it possible for an attacker to render gateway inoperable with certain simple query patterns due to uncontrolled resource consumption. All prior-released versions and configurations are vulnerable. See the associated GitHub Advisories [GHSA-q2f9-x4p4-7xmh](GHSA-q2f9-x4p4-7xmh) and [GHSA-p2q6-pwh5-m6jr](GHSA-p2q6-pwh5-m6jr) for more information. --------- Co-authored-by: Chris Lenfest <[email protected]>
1 parent b6a3301 commit 1462c91

File tree

9 files changed

+1448
-11
lines changed

9 files changed

+1448
-11
lines changed

.changeset/five-suits-drum.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@apollo/query-planner": patch
3+
"@apollo/query-graphs": patch
4+
"@apollo/federation-internals": patch
5+
"@apollo/gateway": patch
6+
---
7+
8+
Corrects a set of denial-of-service (DOS) vulnerabilities that made it possible for an attacker to render gateway inoperable with certain simple query patterns due to uncontrolled resource consumption. All prior-released versions and configurations are vulnerable.
9+
10+
See the associated GitHub Advisories [GHSA-q2f9-x4p4-7xmh](https://github.com/apollographql/federation/security/advisories/GHSA-q2f9-x4p4-7xmh) and [GHSA-p2q6-pwh5-m6jr](https://github.com/apollographql/federation/security/advisories/GHSA-p2q6-pwh5-m6jr) for more information.

.cspell/cspell-dict.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ quer
178178
Queryf
179179
reacheable
180180
reasonse
181+
rebaseable
181182
recusive
182183
redeclaration
183184
refered

gateway-js/src/index.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ export class ApolloGateway implements GatewayInterface {
155155
private experimental_didResolveQueryPlan?: Experimental_DidResolveQueryPlanCallback;
156156
// Used to communicate supergraph updates
157157
private experimental_didUpdateSupergraph?: Experimental_DidUpdateSupergraphCallback;
158+
// Used to disable the recursive selections limit in query planner. Setting
159+
// this to `true` is not advised if gateway is being used to serve queries
160+
// outside your control, as doing so will leave query planner susceptible to
161+
// denial-of-service attacks.
162+
private recursiveSelectionsLimitDisabled: boolean;
163+
// Used to disable the non-local selections limit in query planner. Setting
164+
// this to `true` is not advised if gateway is being used to serve queries
165+
// outside your control, as doing so will leave query planner susceptible to
166+
// denial-of-service attacks.
167+
private nonLocalSelectionsLimitDisabled: boolean;
158168
// how often service defs should be loaded/updated
159169
private pollIntervalInMs?: number;
160170
// Functions to call during gateway cleanup (when stop() is called)
@@ -180,6 +190,22 @@ export class ApolloGateway implements GatewayInterface {
180190
this.experimental_didUpdateSupergraph =
181191
config?.experimental_didUpdateSupergraph;
182192

193+
// Check environment variables to see whether the query planner's recursive
194+
// selections limit should be disabled. Setting this variable to `true` is
195+
// not advised if gateway is being used to serve queries outside your
196+
// control, as doing so will leave query planner susceptible to
197+
// denial-of-service attacks.
198+
this.recursiveSelectionsLimitDisabled =
199+
process.env.APOLLO_DISABLE_SECURITY_RECURSIVE_SELECTIONS_CHECK === 'true';
200+
201+
// Check environment variables to see whether the query planner's non-local
202+
// selections limit should be disabled. Setting this variable to `true` is
203+
// not advised if gateway is being used to serve queries outside your
204+
// control, as doing so will leave query planner susceptible to
205+
// denial-of-service attacks.
206+
this.nonLocalSelectionsLimitDisabled =
207+
process.env.APOLLO_DISABLE_SECURITY_NON_LOCAL_SELECTIONS_CHECK === 'true';
208+
183209
if (isManagedConfig(this.config)) {
184210
this.pollIntervalInMs =
185211
this.config.fallbackPollIntervalInMs ?? this.config.pollIntervalInMs;
@@ -806,7 +832,12 @@ export class ApolloGateway implements GatewayInterface {
806832
{ operationName: request.operationName },
807833
);
808834
// TODO(#631): Can we be sure the query planner has been initialized here?
809-
return this.queryPlanner!.buildQueryPlan(operation);
835+
return this.queryPlanner!.buildQueryPlan(operation, {
836+
recursiveSelectionsLimitDisabled:
837+
this.recursiveSelectionsLimitDisabled,
838+
nonLocalSelectionsLimitDisabled:
839+
this.nonLocalSelectionsLimitDisabled,
840+
});
810841
} catch (err) {
811842
recordExceptions(span, [err], this.config.telemetry);
812843
span.setStatus({ code: SpanStatusCode.ERROR });

internals-js/src/operations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3650,7 +3650,7 @@ class InlineFragmentSelection extends FragmentSelection {
36503650
}
36513651
}
36523652

3653-
class FragmentSpreadSelection extends FragmentSelection {
3653+
export class FragmentSpreadSelection extends FragmentSelection {
36543654
private computedKey: string | undefined;
36553655

36563656
constructor(

query-graphs-js/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export * from './pathContext';
77
export * from './conditionsCaching';
88
export * from './conditionsValidation';
99
export * from './mermaid';
10+
export * from './nonLocalSelectionsEstimation';

0 commit comments

Comments
 (0)