From a9580e05aca83fe9745e12bc36fb67373fe6e139 Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Wed, 2 Jul 2025 08:33:20 -0400 Subject: [PATCH] fix: disable graphql introspection queries when disableIntrospectionInProduction is true (#12982) --- docs/graphql/overview.mdx | 17 +++++++++-------- packages/graphql/src/index.ts | 16 ++++++++++++++++ packages/payload/src/config/defaults.ts | 1 + packages/payload/src/config/types.ts | 11 +++++++++++ 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/docs/graphql/overview.mdx b/docs/graphql/overview.mdx index a31b8b5ad..bff8ca05d 100644 --- a/docs/graphql/overview.mdx +++ b/docs/graphql/overview.mdx @@ -16,14 +16,15 @@ The labels you provide for your Collections and Globals are used to name the Gra At the top of your Payload Config you can define all the options to manage GraphQL. -| Option | Description | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -| `mutations` | Any custom Mutations to be added in addition to what Payload provides. [More](/docs/graphql/extending) | -| `queries` | Any custom Queries to be added in addition to what Payload provides. [More](/docs/graphql/extending) | -| `maxComplexity` | A number used to set the maximum allowed complexity allowed by requests [More](/docs/graphql/overview#query-complexity-limits) | -| `disablePlaygroundInProduction` | A boolean that if false will enable the GraphQL playground, defaults to true. [More](/docs/graphql/overview#graphql-playground) | -| `disable` | A boolean that if true will disable the GraphQL entirely, defaults to false. | -| `validationRules` | A function that takes the ExecutionArgs and returns an array of ValidationRules. | +| Option | Description | +| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `mutations` | Any custom Mutations to be added in addition to what Payload provides. [More](/docs/graphql/extending) | +| `queries` | Any custom Queries to be added in addition to what Payload provides. [More](/docs/graphql/extending) | +| `maxComplexity` | A number used to set the maximum allowed complexity allowed by requests [More](/docs/graphql/overview#query-complexity-limits) | +| `disablePlaygroundInProduction` | A boolean that if false will enable the GraphQL playground in production environments, defaults to true. [More](/docs/graphql/overview#graphql-playground) | +| `disableIntrospectionInProduction` | A boolean that if false will enable the GraphQL introspection in production environments, defaults to true. | +| `disable` | A boolean that if true will disable the GraphQL entirely, defaults to false. | +| `validationRules` | A function that takes the ExecutionArgs and returns an array of ValidationRules. | ## Collections diff --git a/packages/graphql/src/index.ts b/packages/graphql/src/index.ts index 09374d4d7..3dec8ebd7 100644 --- a/packages/graphql/src/index.ts +++ b/packages/graphql/src/index.ts @@ -113,6 +113,7 @@ export function configToSchema(config: SanitizedConfig): { variables: args.variableValues, // onComplete: (complexity) => { console.log('Query Complexity:', complexity); }, }), + ...(config.graphQL.disableIntrospectionInProduction ? [NoProductionIntrospection] : []), ...(typeof config?.graphQL?.validationRules === 'function' ? config.graphQL.validationRules(args) : []), @@ -123,3 +124,18 @@ export function configToSchema(config: SanitizedConfig): { validationRules, } } + +const NoProductionIntrospection: GraphQL.ValidationRule = (context) => ({ + Field(node) { + if (process.env.NODE_ENV === 'production') { + if (node.name.value === '__schema' || node.name.value === '__type') { + context.reportError( + new GraphQL.GraphQLError( + 'GraphQL introspection is not allowed, but the query contained __schema or __type', + { nodes: [node] }, + ), + ) + } + } + }, +}) diff --git a/packages/payload/src/config/defaults.ts b/packages/payload/src/config/defaults.ts index 6689ca8c4..b5a4063bb 100644 --- a/packages/payload/src/config/defaults.ts +++ b/packages/payload/src/config/defaults.ts @@ -123,6 +123,7 @@ export const addDefaultsToConfig = (config: Config): Config => { config.endpoints = config.endpoints ?? [] config.globals = config.globals ?? [] config.graphQL = { + disableIntrospectionInProduction: true, disablePlaygroundInProduction: true, maxComplexity: 1000, schemaOutputFile: `${typeof process?.cwd === 'function' ? process.cwd() : ''}/schema.graphql`, diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index 068ff51c0..ee1b3bc25 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -1029,6 +1029,17 @@ export type Config = { */ graphQL?: { disable?: boolean + /** + * Disable introspection queries in production. + * + * @default true + */ + disableIntrospectionInProduction?: boolean + /** + * Disable the GraphQL Playground in production. + * + * @default true + */ disablePlaygroundInProduction?: boolean maxComplexity?: number /**