VYPR
High severityNVD Advisory· Published Feb 4, 2026· Updated Feb 4, 2026

Apollo Server is vulnerable to denial of service with `startStandaloneServer`

CVE-2026-23897

Description

Apollo Server is an open-source, spec-compliant GraphQL server that's compatible with any GraphQL client, including Apollo Client. In versions from 2.0.0 to 3.13.0, 4.2.0 to before 4.13.0, and 5.0.0 to before 5.4.0, the default configuration of startStandaloneServer from @apollo/server/standalone is vulnerable to denial of service (DoS) attacks through specially crafted request bodies with exotic character set encodings. This issue does not affect users that use @apollo/server as a dependency for integration packages, like @as-integrations/express5 or @as-integrations/next, only direct usage of startStandaloneServer.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Apollo Server's startStandaloneServer default configuration is vulnerable to DoS via crafted request bodies with exotic character set encodings.

Vulnerability

Overview

Apollo Server, an open-source GraphQL server, contains a denial-of-service (DoS) vulnerability in the default configuration of startStandaloneServer from @apollo/server/standalone. The issue arises because the server does not properly validate character set encodings in incoming request bodies, allowing an attacker to send specially crafted payloads with exotic encodings that can exhaust server resources [1][4].

Attack

Vector

An attacker can exploit this vulnerability by sending HTTP requests with a Content-Type header specifying an unusual character encoding (e.g., UTF-7 or ISO-2022-JP) along with a maliciously crafted JSON body. The server's default body parser attempts to decode these encodings, leading to excessive CPU consumption or memory allocation. No authentication is required, and the attack can be launched over the network-based, targeting the standalone server's HTTP endpoint [2][4].

Impact

Successful exploitation results in a denial of service, rendering the GraphQL server unresponsive to legitimate requests. This can disrupt services that rely on startStandaloneServer for production deployments, as the vulnerability affects all versions from 2.0.0 to 3.13.0, 4.2.0 to before 4.13.0, and 5.0.0 to before 5.4.0 [1][4].

Mitigation

Patches are available in @apollo/server versions 5.4.0 and 4.13.0, which restrict accepted encodings to UTF-8, UTF-16, and UTF-32, rejecting others with a 415 Unsupported Media Type error [2][4]. Users of end-of-life versions v2 and v3 are advised to upgrade to a supported version or switch to an integration package like apollo-server-express for better security control [4].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
apollo-servernpm
>= 2.0.0, <= 3.13.0
@apollo/servernpm
>= 4.2.0, < 4.13.04.13.0
@apollo/servernpm
>= 5.0.0, < 5.4.05.4.0

Affected products

3

Patches

2
e9d49d163a86

Merge commit from fork

https://github.com/apollographql/apollo-serverLenz Weber-TronicFeb 4, 2026via ghsa
6 files changed · +315 295
  • .changeset/nice-pandas-shake.md+18 0 added
    @@ -0,0 +1,18 @@
    +---
    +'@apollo/server': minor
    +---
    +
    +⚠️ SECURITY `@apollo/server/standalone`:
    +
    +The default configuration of `startStandaloneServer` was vulnerable to denial of service (DoS) attacks through specially crafted request bodies with exotic character set encodings.
    +
    +In accordance with [RFC 7159](https://datatracker.ietf.org/doc/html/rfc7159#section-8.1), we now only accept request bodies encoded in UTF-8, UTF-16 (LE or BE), or UTF-32 (LE or BE).
    +Any other character set will be rejected with a `415 Unsupported Media Type` error.
    +Additionally, upstream libraries used by this version of Apollo Server may not support all of these encodings, so some requests may still fail even if they pass this check.
    +
    +**If you were not using `startStandaloneServer`, you were not affected by this vulnerability.**
    +
    +Generally, please note that we provide `startStandaloneServer` as a convenience tool for quickly getting started with Apollo Server.
    +For production deployments, we recommend using Apollo Server with a more fully-featured web server framework such as Express, Koa, or Fastify, where you have more control over security-related configuration options.
    +
    +Also please note that **Apollo Server 4.x is considered EOL as of January 26, 2026, and Apollo no longer commits to providing support or updates for it**. Please prioritize migrating to Apollo Server 5.x for continued support and updates.
    
  • package.json+2 0 modified
    @@ -51,6 +51,7 @@
         "@rollup/plugin-commonjs": "28.0.6",
         "@types/async-retry": "1.4.9",
         "@types/compression": "1.8.1",
    +    "@types/content-type": "^1.1.9",
         "@types/cors": "2.8.19",
         "@types/express": "4.17.23",
         "@types/express-serve-static-core": "4.19.6",
    @@ -82,6 +83,7 @@
         "graphql": "16.11.0",
         "graphql-subscriptions": "3.0.0",
         "graphql-tag": "2.12.6",
    +    "iconv-lite": "^0.7.2",
         "jest": "29.7.0",
         "jest-config": "29.7.0",
         "jest-junit": "16.0.0",
    
  • package-lock.json+132 294 modified
    @@ -23,6 +23,7 @@
             "@rollup/plugin-commonjs": "28.0.6",
             "@types/async-retry": "1.4.9",
             "@types/compression": "1.8.1",
    +        "@types/content-type": "^1.1.9",
             "@types/cors": "2.8.19",
             "@types/express": "4.17.23",
             "@types/express-serve-static-core": "4.19.6",
    @@ -54,6 +55,7 @@
             "graphql": "16.11.0",
             "graphql-subscriptions": "3.0.0",
             "graphql-tag": "2.12.6",
    +        "iconv-lite": "^0.7.2",
             "jest": "29.7.0",
             "jest-config": "29.7.0",
             "jest-junit": "16.0.0",
    @@ -682,6 +684,7 @@
         "node_modules/@babel/core": {
           "version": "7.17.9",
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "@ampproject/remapping": "^2.1.0",
             "@babel/code-frame": "^7.16.7",
    @@ -2417,30 +2420,6 @@
             "node": ">=14.6"
           }
         },
    -    "node_modules/@cspotcode/source-map-support": {
    -      "version": "0.8.1",
    -      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
    -      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
    -      "optional": true,
    -      "peer": true,
    -      "dependencies": {
    -        "@jridgewell/trace-mapping": "0.3.9"
    -      },
    -      "engines": {
    -        "node": ">=12"
    -      }
    -    },
    -    "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
    -      "version": "0.3.9",
    -      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
    -      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
    -      "optional": true,
    -      "peer": true,
    -      "dependencies": {
    -        "@jridgewell/resolve-uri": "^3.0.3",
    -        "@jridgewell/sourcemap-codec": "^1.4.10"
    -      }
    -    },
         "node_modules/@eslint-community/eslint-utils": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz",
    @@ -3556,13 +3535,6 @@
           "dev": true,
           "license": "BSD-3-Clause"
         },
    -    "node_modules/@iarna/toml": {
    -      "version": "2.2.5",
    -      "dev": true,
    -      "license": "ISC",
    -      "optional": true,
    -      "peer": true
    -    },
         "node_modules/@istanbuljs/load-nyc-config": {
           "version": "1.1.0",
           "license": "ISC",
    @@ -3721,6 +3693,7 @@
           "version": "29.7.0",
           "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
           "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
    +      "peer": true,
           "dependencies": {
             "@jest/environment": "^29.7.0",
             "@jest/expect": "^29.7.0",
    @@ -4243,6 +4216,7 @@
           "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "engines": {
             "node": ">=12"
           },
    @@ -4309,34 +4283,6 @@
             "node": ">= 10"
           }
         },
    -    "node_modules/@tsconfig/node10": {
    -      "version": "1.0.9",
    -      "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
    -      "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
    -      "optional": true,
    -      "peer": true
    -    },
    -    "node_modules/@tsconfig/node12": {
    -      "version": "1.0.11",
    -      "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
    -      "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
    -      "optional": true,
    -      "peer": true
    -    },
    -    "node_modules/@tsconfig/node14": {
    -      "version": "1.0.3",
    -      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
    -      "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
    -      "optional": true,
    -      "peer": true
    -    },
    -    "node_modules/@tsconfig/node16": {
    -      "version": "1.0.3",
    -      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
    -      "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
    -      "optional": true,
    -      "peer": true
    -    },
         "node_modules/@types/async-retry": {
           "version": "1.4.9",
           "resolved": "https://registry.npmjs.org/@types/async-retry/-/async-retry-1.4.9.tgz",
    @@ -4411,6 +4357,13 @@
             "@types/node": "*"
           }
         },
    +    "node_modules/@types/content-type": {
    +      "version": "1.1.9",
    +      "resolved": "https://registry.npmjs.org/@types/content-type/-/content-type-1.1.9.tgz",
    +      "integrity": "sha512-Hq9IMnfekuOCsEmYl4QX2HBrT+XsfXiupfrLLY8Dcf3Puf4BkBOxSbWYTITSOQAhJoYPBez+b4MJRpIYL65z8A==",
    +      "dev": true,
    +      "license": "MIT"
    +    },
         "node_modules/@types/cookiejar": {
           "version": "2.1.5",
           "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz",
    @@ -4774,6 +4727,7 @@
           "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
           "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
           "dev": true,
    +      "peer": true,
           "dependencies": {
             "@typescript-eslint/scope-manager": "5.62.0",
             "@typescript-eslint/types": "5.62.0",
    @@ -5048,7 +5002,8 @@
           "version": "8.9.0",
           "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
           "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
    -      "devOptional": true,
    +      "dev": true,
    +      "peer": true,
           "bin": {
             "acorn": "bin/acorn"
           },
    @@ -5065,16 +5020,6 @@
             "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
           }
         },
    -    "node_modules/acorn-walk": {
    -      "version": "8.2.0",
    -      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
    -      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
    -      "optional": true,
    -      "peer": true,
    -      "engines": {
    -        "node": ">=0.4.0"
    -      }
    -    },
         "node_modules/agent-base": {
           "version": "6.0.2",
           "dev": true,
    @@ -5203,12 +5148,6 @@
             "node": ">= 8"
           }
         },
    -    "node_modules/arg": {
    -      "version": "4.1.3",
    -      "license": "MIT",
    -      "optional": true,
    -      "peer": true
    -    },
         "node_modules/argparse": {
           "version": "2.0.1",
           "dev": true,
    @@ -5659,6 +5598,18 @@
             "ms": "2.0.0"
           }
         },
    +    "node_modules/body-parser/node_modules/iconv-lite": {
    +      "version": "0.4.24",
    +      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
    +      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
    +      "license": "MIT",
    +      "dependencies": {
    +        "safer-buffer": ">= 2.1.2 < 3"
    +      },
    +      "engines": {
    +        "node": ">=0.10.0"
    +      }
    +    },
         "node_modules/body-parser/node_modules/ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
    @@ -5698,6 +5649,7 @@
               "url": "https://tidelift.com/funding/github/npm/browserslist"
             }
           ],
    +      "peer": true,
           "dependencies": {
             "caniuse-lite": "^1.0.30001400",
             "electron-to-chromium": "^1.4.251",
    @@ -6365,6 +6317,7 @@
           "version": "1.0.5",
           "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
           "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
    +      "license": "MIT",
           "engines": {
             "node": ">= 0.6"
           }
    @@ -6429,16 +6382,6 @@
             "node": ">=10"
           }
         },
    -    "node_modules/cosmiconfig-toml-loader": {
    -      "version": "1.0.0",
    -      "dev": true,
    -      "license": "MIT",
    -      "optional": true,
    -      "peer": true,
    -      "dependencies": {
    -        "@iarna/toml": "^2.2.5"
    -      }
    -    },
         "node_modules/create-jest": {
           "version": "29.7.0",
           "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
    @@ -6459,12 +6402,6 @@
             "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
           }
         },
    -    "node_modules/create-require": {
    -      "version": "1.1.1",
    -      "license": "MIT",
    -      "optional": true,
    -      "peer": true
    -    },
         "node_modules/cross-fetch": {
           "version": "3.1.5",
           "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
    @@ -7027,15 +6964,6 @@
             "wrappy": "1"
           }
         },
    -    "node_modules/diff": {
    -      "version": "4.0.2",
    -      "license": "BSD-3-Clause",
    -      "optional": true,
    -      "peer": true,
    -      "engines": {
    -        "node": ">=0.3.1"
    -      }
    -    },
         "node_modules/diff-sequences": {
           "version": "29.6.3",
           "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
    @@ -7488,6 +7416,7 @@
           "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "@eslint-community/eslint-utils": "^4.2.0",
             "@eslint-community/regexpp": "^4.6.1",
    @@ -8079,6 +8008,19 @@
             "node": ">=4"
           }
         },
    +    "node_modules/external-editor/node_modules/iconv-lite": {
    +      "version": "0.4.24",
    +      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
    +      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
    +      "dev": true,
    +      "license": "MIT",
    +      "dependencies": {
    +        "safer-buffer": ">= 2.1.2 < 3"
    +      },
    +      "engines": {
    +        "node": ">=0.10.0"
    +      }
    +    },
         "node_modules/extract-files": {
           "version": "11.0.0",
           "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz",
    @@ -8754,6 +8696,7 @@
           "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz",
           "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==",
           "license": "MIT",
    +      "peer": true,
           "engines": {
             "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
           }
    @@ -8883,6 +8826,7 @@
           "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.11.2.tgz",
           "integrity": "sha512-4EiZ3/UXYcjm+xFGP544/yW1+DVI8ZpKASFbzrV5EDTFWJp0ZvLl4Dy2fSZAzz9imKp5pZMIcjB0x/H69Pv/6w==",
           "devOptional": true,
    +      "peer": true,
           "engines": {
             "node": ">=10"
           },
    @@ -9101,13 +9045,20 @@
           }
         },
         "node_modules/iconv-lite": {
    -      "version": "0.4.24",
    +      "version": "0.7.2",
    +      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
    +      "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "safer-buffer": ">= 2.1.2 < 3"
    +        "safer-buffer": ">= 2.1.2 < 3.0.0"
           },
           "engines": {
             "node": ">=0.10.0"
    +      },
    +      "funding": {
    +        "type": "opencollective",
    +        "url": "https://opencollective.com/express"
           }
         },
         "node_modules/ieee754": {
    @@ -10034,6 +9985,7 @@
           "version": "29.7.0",
           "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
           "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
    +      "peer": true,
           "dependencies": {
             "@jest/core": "^29.7.0",
             "@jest/types": "^29.6.3",
    @@ -11030,7 +10982,7 @@
         },
         "node_modules/make-error": {
           "version": "1.3.6",
    -      "devOptional": true,
    +      "dev": true,
           "license": "ISC"
         },
         "node_modules/make-fetch-happen": {
    @@ -12323,6 +12275,18 @@
             "node": ">= 0.8"
           }
         },
    +    "node_modules/raw-body/node_modules/iconv-lite": {
    +      "version": "0.4.24",
    +      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
    +      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
    +      "license": "MIT",
    +      "dependencies": {
    +        "safer-buffer": ">= 2.1.2 < 3"
    +      },
    +      "engines": {
    +        "node": ">=0.10.0"
    +      }
    +    },
         "node_modules/react-is": {
           "version": "16.13.1",
           "license": "MIT"
    @@ -12651,6 +12615,7 @@
           "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "bin": {
             "rollup": "dist/bin/rollup"
           },
    @@ -13762,50 +13727,6 @@
           "dev": true,
           "license": "MIT"
         },
    -    "node_modules/ts-node": {
    -      "version": "10.9.1",
    -      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
    -      "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
    -      "optional": true,
    -      "peer": true,
    -      "dependencies": {
    -        "@cspotcode/source-map-support": "^0.8.0",
    -        "@tsconfig/node10": "^1.0.7",
    -        "@tsconfig/node12": "^1.0.7",
    -        "@tsconfig/node14": "^1.0.0",
    -        "@tsconfig/node16": "^1.0.2",
    -        "acorn": "^8.4.1",
    -        "acorn-walk": "^8.1.1",
    -        "arg": "^4.1.0",
    -        "create-require": "^1.1.0",
    -        "diff": "^4.0.1",
    -        "make-error": "^1.1.1",
    -        "v8-compile-cache-lib": "^3.0.1",
    -        "yn": "3.1.1"
    -      },
    -      "bin": {
    -        "ts-node": "dist/bin.js",
    -        "ts-node-cwd": "dist/bin-cwd.js",
    -        "ts-node-esm": "dist/bin-esm.js",
    -        "ts-node-script": "dist/bin-script.js",
    -        "ts-node-transpile-only": "dist/bin-transpile.js",
    -        "ts-script": "dist/bin-script-deprecated.js"
    -      },
    -      "peerDependencies": {
    -        "@swc/core": ">=1.2.50",
    -        "@swc/wasm": ">=1.2.50",
    -        "@types/node": "*",
    -        "typescript": ">=2.7"
    -      },
    -      "peerDependenciesMeta": {
    -        "@swc/core": {
    -          "optional": true
    -        },
    -        "@swc/wasm": {
    -          "optional": true
    -        }
    -      }
    -    },
         "node_modules/tsconfig-paths": {
           "version": "3.15.0",
           "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
    @@ -13992,8 +13913,9 @@
           "version": "5.4.5",
           "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
           "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
    -      "devOptional": true,
    +      "dev": true,
           "license": "Apache-2.0",
    +      "peer": true,
           "bin": {
             "tsc": "bin/tsc",
             "tsserver": "bin/tsserver"
    @@ -14223,13 +14145,6 @@
             "uuid": "dist/bin/uuid"
           }
         },
    -    "node_modules/v8-compile-cache-lib": {
    -      "version": "3.0.1",
    -      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
    -      "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
    -      "optional": true,
    -      "peer": true
    -    },
         "node_modules/v8-to-istanbul": {
           "version": "9.1.0",
           "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz",
    @@ -14478,6 +14393,7 @@
           "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
           "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
           "dev": true,
    +      "peer": true,
           "engines": {
             "node": ">=10.0.0"
           },
    @@ -14567,15 +14483,6 @@
             "node": ">=12"
           }
         },
    -    "node_modules/yn": {
    -      "version": "3.1.1",
    -      "license": "MIT",
    -      "optional": true,
    -      "peer": true,
    -      "engines": {
    -        "node": ">=6"
    -      }
    -    },
         "node_modules/yocto-queue": {
           "version": "0.1.0",
           "license": "MIT",
    @@ -14683,6 +14590,7 @@
             "@types/express-serve-static-core": "^4.17.30",
             "@types/node-fetch": "^2.6.1",
             "async-retry": "^1.2.1",
    +        "content-type": "^1.0.5",
             "cors": "^2.8.5",
             "express": "^4.21.1",
             "loglevel": "^1.6.8",
    @@ -14917,6 +14825,7 @@
             "@types/express-serve-static-core": "^4.17.30",
             "@types/node-fetch": "^2.6.1",
             "async-retry": "^1.2.1",
    +        "content-type": "^1.0.5",
             "cors": "^2.8.5",
             "express": "^4.21.1",
             "loglevel": "^1.6.8",
    @@ -15235,6 +15144,7 @@
         },
         "@babel/core": {
           "version": "7.17.9",
    +      "peer": true,
           "requires": {
             "@ampproject/remapping": "^2.1.0",
             "@babel/code-frame": "^7.16.7",
    @@ -16588,29 +16498,6 @@
           "integrity": "sha512-znwc9IlgGUPioHGshP/zyM8HsuYg1OY5S7HSiVXARh5H8RqcyBsnyn8abc0PPhqPrfDy9Fh5xHsAEPZ55dl1vQ==",
           "dev": true
         },
    -    "@cspotcode/source-map-support": {
    -      "version": "0.8.1",
    -      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
    -      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
    -      "optional": true,
    -      "peer": true,
    -      "requires": {
    -        "@jridgewell/trace-mapping": "0.3.9"
    -      },
    -      "dependencies": {
    -        "@jridgewell/trace-mapping": {
    -          "version": "0.3.9",
    -          "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
    -          "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
    -          "optional": true,
    -          "peer": true,
    -          "requires": {
    -            "@jridgewell/resolve-uri": "^3.0.3",
    -            "@jridgewell/sourcemap-codec": "^1.4.10"
    -          }
    -        }
    -      }
    -    },
         "@eslint-community/eslint-utils": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz",
    @@ -17551,12 +17438,6 @@
           "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
           "dev": true
         },
    -    "@iarna/toml": {
    -      "version": "2.2.5",
    -      "dev": true,
    -      "optional": true,
    -      "peer": true
    -    },
         "@istanbuljs/load-nyc-config": {
           "version": "1.1.0",
           "requires": {
    @@ -17678,6 +17559,7 @@
           "version": "29.7.0",
           "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
           "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
    +      "peer": true,
           "requires": {
             "@jest/environment": "^29.7.0",
             "@jest/expect": "^29.7.0",
    @@ -18082,7 +17964,8 @@
               "version": "4.0.2",
               "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
               "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
    -          "dev": true
    +          "dev": true,
    +          "peer": true
             }
           }
         },
    @@ -18130,34 +18013,6 @@
           "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
           "dev": true
         },
    -    "@tsconfig/node10": {
    -      "version": "1.0.9",
    -      "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
    -      "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
    -      "optional": true,
    -      "peer": true
    -    },
    -    "@tsconfig/node12": {
    -      "version": "1.0.11",
    -      "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
    -      "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
    -      "optional": true,
    -      "peer": true
    -    },
    -    "@tsconfig/node14": {
    -      "version": "1.0.3",
    -      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
    -      "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
    -      "optional": true,
    -      "peer": true
    -    },
    -    "@tsconfig/node16": {
    -      "version": "1.0.3",
    -      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
    -      "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
    -      "optional": true,
    -      "peer": true
    -    },
         "@types/async-retry": {
           "version": "1.4.9",
           "resolved": "https://registry.npmjs.org/@types/async-retry/-/async-retry-1.4.9.tgz",
    @@ -18229,6 +18084,12 @@
             "@types/node": "*"
           }
         },
    +    "@types/content-type": {
    +      "version": "1.1.9",
    +      "resolved": "https://registry.npmjs.org/@types/content-type/-/content-type-1.1.9.tgz",
    +      "integrity": "sha512-Hq9IMnfekuOCsEmYl4QX2HBrT+XsfXiupfrLLY8Dcf3Puf4BkBOxSbWYTITSOQAhJoYPBez+b4MJRpIYL65z8A==",
    +      "dev": true
    +    },
         "@types/cookiejar": {
           "version": "2.1.5",
           "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz",
    @@ -18551,6 +18412,7 @@
           "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
           "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
           "dev": true,
    +      "peer": true,
           "requires": {
             "@typescript-eslint/scope-manager": "5.62.0",
             "@typescript-eslint/types": "5.62.0",
    @@ -18730,7 +18592,8 @@
           "version": "8.9.0",
           "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
           "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
    -      "devOptional": true
    +      "dev": true,
    +      "peer": true
         },
         "acorn-jsx": {
           "version": "5.3.2",
    @@ -18739,13 +18602,6 @@
           "dev": true,
           "requires": {}
         },
    -    "acorn-walk": {
    -      "version": "8.2.0",
    -      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
    -      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
    -      "optional": true,
    -      "peer": true
    -    },
         "agent-base": {
           "version": "6.0.2",
           "dev": true,
    @@ -18830,11 +18686,6 @@
             "picomatch": "^2.0.4"
           }
         },
    -    "arg": {
    -      "version": "4.1.3",
    -      "optional": true,
    -      "peer": true
    -    },
         "argparse": {
           "version": "2.0.1",
           "dev": true
    @@ -19152,6 +19003,14 @@
                 "ms": "2.0.0"
               }
             },
    +        "iconv-lite": {
    +          "version": "0.4.24",
    +          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
    +          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
    +          "requires": {
    +            "safer-buffer": ">= 2.1.2 < 3"
    +          }
    +        },
             "ms": {
               "version": "2.0.0",
               "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
    @@ -19178,6 +19037,7 @@
           "version": "4.21.4",
           "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
           "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
    +      "peer": true,
           "requires": {
             "caniuse-lite": "^1.0.30001400",
             "electron-to-chromium": "^1.4.251",
    @@ -19698,15 +19558,6 @@
             "yaml": "^1.10.0"
           }
         },
    -    "cosmiconfig-toml-loader": {
    -      "version": "1.0.0",
    -      "dev": true,
    -      "optional": true,
    -      "peer": true,
    -      "requires": {
    -        "@iarna/toml": "^2.2.5"
    -      }
    -    },
         "create-jest": {
           "version": "29.7.0",
           "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
    @@ -19721,11 +19572,6 @@
             "prompts": "^2.0.1"
           }
         },
    -    "create-require": {
    -      "version": "1.1.1",
    -      "optional": true,
    -      "peer": true
    -    },
         "cross-fetch": {
           "version": "3.1.5",
           "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
    @@ -20108,11 +19954,6 @@
             "wrappy": "1"
           }
         },
    -    "diff": {
    -      "version": "4.0.2",
    -      "optional": true,
    -      "peer": true
    -    },
         "diff-sequences": {
           "version": "29.6.3",
           "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
    @@ -20461,6 +20302,7 @@
           "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
           "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
           "dev": true,
    +      "peer": true,
           "requires": {
             "@eslint-community/eslint-utils": "^4.2.0",
             "@eslint-community/regexpp": "^4.6.1",
    @@ -20882,6 +20724,17 @@
             "chardet": "^0.7.0",
             "iconv-lite": "^0.4.24",
             "tmp": "^0.0.33"
    +      },
    +      "dependencies": {
    +        "iconv-lite": {
    +          "version": "0.4.24",
    +          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
    +          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
    +          "dev": true,
    +          "requires": {
    +            "safer-buffer": ">= 2.1.2 < 3"
    +          }
    +        }
           }
         },
         "extract-files": {
    @@ -21362,7 +21215,8 @@
         "graphql": {
           "version": "16.11.0",
           "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz",
    -      "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="
    +      "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==",
    +      "peer": true
         },
         "graphql-config": {
           "version": "4.5.0",
    @@ -21447,6 +21301,7 @@
           "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.11.2.tgz",
           "integrity": "sha512-4EiZ3/UXYcjm+xFGP544/yW1+DVI8ZpKASFbzrV5EDTFWJp0ZvLl4Dy2fSZAzz9imKp5pZMIcjB0x/H69Pv/6w==",
           "devOptional": true,
    +      "peer": true,
           "requires": {}
         },
         "has-bigints": {
    @@ -21600,9 +21455,12 @@
           }
         },
         "iconv-lite": {
    -      "version": "0.4.24",
    +      "version": "0.7.2",
    +      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
    +      "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
    +      "dev": true,
           "requires": {
    -        "safer-buffer": ">= 2.1.2 < 3"
    +        "safer-buffer": ">= 2.1.2 < 3.0.0"
           }
         },
         "ieee754": {
    @@ -22198,6 +22056,7 @@
           "version": "29.7.0",
           "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
           "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
    +      "peer": true,
           "requires": {
             "@jest/core": "^29.7.0",
             "@jest/types": "^29.6.3",
    @@ -22937,7 +22796,7 @@
         },
         "make-error": {
           "version": "1.3.6",
    -      "devOptional": true
    +      "dev": true
         },
         "make-fetch-happen": {
           "version": "11.1.1",
    @@ -23804,6 +23663,16 @@
             "http-errors": "2.0.0",
             "iconv-lite": "0.4.24",
             "unpipe": "1.0.0"
    +      },
    +      "dependencies": {
    +        "iconv-lite": {
    +          "version": "0.4.24",
    +          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
    +          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
    +          "requires": {
    +            "safer-buffer": ">= 2.1.2 < 3"
    +          }
    +        }
           }
         },
         "react-is": {
    @@ -24038,6 +23907,7 @@
           "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz",
           "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
           "dev": true,
    +      "peer": true,
           "requires": {
             "fsevents": "~2.3.2"
           }
    @@ -24794,28 +24664,6 @@
           "version": "2.2.4",
           "dev": true
         },
    -    "ts-node": {
    -      "version": "10.9.1",
    -      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
    -      "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
    -      "optional": true,
    -      "peer": true,
    -      "requires": {
    -        "@cspotcode/source-map-support": "^0.8.0",
    -        "@tsconfig/node10": "^1.0.7",
    -        "@tsconfig/node12": "^1.0.7",
    -        "@tsconfig/node14": "^1.0.0",
    -        "@tsconfig/node16": "^1.0.2",
    -        "acorn": "^8.4.1",
    -        "acorn-walk": "^8.1.1",
    -        "arg": "^4.1.0",
    -        "create-require": "^1.1.0",
    -        "diff": "^4.0.1",
    -        "make-error": "^1.1.1",
    -        "v8-compile-cache-lib": "^3.0.1",
    -        "yn": "3.1.1"
    -      }
    -    },
         "tsconfig-paths": {
           "version": "3.15.0",
           "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
    @@ -24947,7 +24795,8 @@
           "version": "5.4.5",
           "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
           "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
    -      "devOptional": true
    +      "dev": true,
    +      "peer": true
         },
         "ua-parser-js": {
           "version": "0.7.35",
    @@ -25095,13 +24944,6 @@
           "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
           "dev": true
         },
    -    "v8-compile-cache-lib": {
    -      "version": "3.0.1",
    -      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
    -      "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
    -      "optional": true,
    -      "peer": true
    -    },
         "v8-to-istanbul": {
           "version": "9.1.0",
           "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz",
    @@ -25287,6 +25129,7 @@
           "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
           "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
           "dev": true,
    +      "peer": true,
           "requires": {}
         },
         "xdg-basedir": {
    @@ -25337,11 +25180,6 @@
           "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
           "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
         },
    -    "yn": {
    -      "version": "3.1.1",
    -      "optional": true,
    -      "peer": true
    -    },
         "yocto-queue": {
           "version": "0.1.0"
         },
    
  • packages/server/package.json+1 0 modified
    @@ -148,6 +148,7 @@
         "@types/express-serve-static-core": "^4.17.30",
         "@types/node-fetch": "^2.6.1",
         "async-retry": "^1.2.1",
    +    "content-type": "^1.0.5",
         "cors": "^2.8.5",
         "express": "^4.21.1",
         "loglevel": "^1.6.8",
    
  • packages/server/src/standalone/index.ts+26 1 modified
    @@ -1,6 +1,7 @@
     import type { WithRequired } from '@apollo/utils.withrequired';
     import cors from 'cors';
     import express from 'express';
    +import { parse as parseContentType } from 'content-type';
     import http, { type IncomingMessage, type ServerResponse } from 'http';
     import type { ListenOptions } from 'net';
     import type { ApolloServer } from '../ApolloServer.js';
    @@ -29,6 +30,14 @@ export interface StartStandaloneServerOptions<TContext extends BaseContext> {
       >;
     }
     
    +// according to RFC8259, only UTF-8 is allowed in JSON text
    +// (see https://datatracker.ietf.org/doc/html/rfc8259#section-8.1)
    +// RFC 7159 also specifies that JSON could be UTF-16 or UTF-32,
    +// so we allow for that, too
    +// note that the upstream dependencies of Apollo Client 4 do not work with UTF-32,
    +// so they will likely fail, even though we allow it here
    +const validCharset = /^utf-(8|((16|32)(le|be)?))$/i;
    +
     export async function startStandaloneServer(
       server: ApolloServer<BaseContext>,
       options?: StartStandaloneServerOptions<BaseContext> & {
    @@ -57,7 +66,23 @@ export async function startStandaloneServer<TContext extends BaseContext>(
       const context = options?.context ?? (async () => ({}) as TContext);
       app.use(
         cors(),
    -    express.json({ limit: '50mb' }),
    +    express.json({
    +      verify(req) {
    +        const charset = parseContentType(req).parameters.charset || 'utf-8';
    +        if (!charset.match(validCharset)) {
    +          throw Object.assign(
    +            new Error(`unsupported charset "${charset.toUpperCase()}"`),
    +            {
    +              status: 415,
    +              name: 'UnsupportedMediaTypeError',
    +              charset,
    +              type: 'charset.unsupported',
    +            },
    +          );
    +        }
    +      },
    +      limit: '50mb',
    +    }),
         expressMiddleware(server, { context }),
       );
     
    
  • packages/server/src/__tests__/standalone/standaloneSpecific.test.ts+136 0 modified
    @@ -1,5 +1,6 @@
     import { describe, expect, it } from '@jest/globals';
     import fetch from 'node-fetch';
    +import { encode } from 'iconv-lite';
     import { ApolloServer } from '../..';
     import { startStandaloneServer } from '../../standalone';
     
    @@ -142,3 +143,138 @@ describe('Configuration', () => {
         await server.stop();
       });
     });
    +
    +describe('Request body charset handling', () => {
    +  it.each<{ encoding: string; charset: string | null }>([
    +    { encoding: 'utf-8', charset: null },
    +    { encoding: 'utf-8', charset: 'UTF-8' },
    +    { encoding: 'utf-8', charset: 'utf-8' },
    +    { encoding: 'utf-16', charset: 'utf-16' },
    +    { encoding: 'utf-16le', charset: 'utf-16le' },
    +    { encoding: 'utf-16be', charset: 'utf-16be' },
    +  ])(
    +    'allows $encoding in request body (passed in header: $charset)',
    +    async ({ encoding, charset }) => {
    +      const server = new ApolloServer({
    +        typeDefs: `type Query { hello(name: String!): String! }`,
    +        resolvers: {
    +          Query: {
    +            hello: (_, { name }) => `hello ${name}!`,
    +          },
    +        },
    +      });
    +      const { url } = await startStandaloneServer(server, {
    +        listen: { port: 0 },
    +      });
    +      const result = await fetch(url, {
    +        method: 'POST',
    +        headers: {
    +          'Content-Type': `application/json${charset ? `;charset=${charset}` : ''}`,
    +        },
    +        body: encode(
    +          JSON.stringify({
    +            query: `query($name: String!){hello(name: $name)}`,
    +            variables: { name: '👻' },
    +          }),
    +          encoding,
    +        ),
    +      });
    +
    +      if (result.ok === false) {
    +        console.error(await result.text());
    +      }
    +      expect(result.ok).toBe(true);
    +      expect(result.status).toBe(200);
    +      expect(await result.json()).toEqual({
    +        data: { hello: 'hello 👻!' },
    +      });
    +
    +      await server.stop();
    +    },
    +  );
    +
    +  it.each<{
    +    encoding: string;
    +    charset: string | null;
    +    status: number;
    +    expectedError: RegExp;
    +  }>([
    +    // exotic encodings
    +    {
    +      encoding: 'win1251',
    +      charset: 'win1251',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;WIN1251&quot;/,
    +    },
    +    {
    +      encoding: 'iso-8859-1',
    +      charset: 'iso-8859-1',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;ISO-8859-1&quot;/,
    +    },
    +    {
    +      encoding: 'windows936',
    +      charset: 'windows936',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;WINDOWS936&quot;/,
    +    },
    +    {
    +      encoding: 'utf-7',
    +      charset: 'utf-7',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;UTF-7&quot;/,
    +    },
    +    {
    +      encoding: 'utf-7-imap',
    +      charset: 'utf-7-imap',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;UTF-7-IMAP&quot;/,
    +    },
    +    // sending one encoding but declaring another
    +    {
    +      encoding: 'utf-7',
    +      charset: 'utf-8',
    +      status: 400,
    +      expectedError: /SyntaxError: Unexpected token .* is not valid JSON/,
    +    },
    +  ])(
    +    'fails with $status for $encoding in request body (passed in header: $charset)',
    +    async ({ encoding, charset, expectedError, status }) => {
    +      const server = new ApolloServer({
    +        typeDefs: `type Query { hello(name: String!): String! }`,
    +        resolvers: {
    +          Query: {
    +            hello: (_, { name }) => `hello ${name}!`,
    +          },
    +        },
    +      });
    +      const { url } = await startStandaloneServer(server, {
    +        listen: { port: 0 },
    +      });
    +      const result = await fetch(url, {
    +        method: 'POST',
    +        headers: {
    +          'Content-Type': `application/json${charset ? `;charset=${charset}` : ''}`,
    +        },
    +        body: encode(
    +          JSON.stringify({
    +            query: `query($name: String!){hello(name: $name)}`,
    +            variables: { name: '👻' },
    +          }),
    +          encoding,
    +        ),
    +      });
    +
    +      expect(result.ok).toBe(false);
    +      expect(result.status).toBe(status);
    +      expect(await result.text()).toMatch(expectedError);
    +
    +      await server.stop();
    +    },
    +  );
    +});
    
d25a5bdc3778

Merge commit from fork

https://github.com/apollographql/apollo-serverLenz Weber-TronicFeb 4, 2026via ghsa
8 files changed · +268 12
  • .changeset/thirty-camels-deny.md+18 0 added
    @@ -0,0 +1,18 @@
    +---
    +'@apollo/server': minor
    +---
    +
    +⚠️ SECURITY `@apollo/server/standalone`:
    +
    +The default configuration of `startStandaloneServer` was vulnerable to denial of service (DoS) attacks through specially crafted request bodies with exotic character set encodings.
    +
    +In accordance with [RFC 7159](https://datatracker.ietf.org/doc/html/rfc7159#section-8.1), we now only accept request bodies encoded in UTF-8, UTF-16 (LE or BE), or UTF-32 (LE or BE).
    +Any other character set will be rejected with a `415 Unsupported Media Type` error.
    +Note that the more recent JSON RFC, [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259#section-8.1), is more strict and will only allow UTF-8.
    +Since this is a minor release, we have chosen to remain compatible with the more permissive RFC 7159 for now.
    +In a future major release, we may tighten this restriction further to only allow UTF-8.
    +
    +**If you were not using `startStandaloneServer`, you were not affected by this vulnerability.**
    +
    +Generally, please note that we provide `startStandaloneServer` as a convenience tool for quickly getting started with Apollo Server.
    +For production deployments, we recommend using Apollo Server with a more fully-featured web server framework such as Express, Koa, or Fastify, where you have more control over security-related configuration options.
    
  • docs/source/api/standalone.mdx+30 4 modified
    @@ -9,9 +9,11 @@ This API reference documents the `startStandaloneServer` function.
     
     ## Overview
     
    -This `startStandaloneServer` function helps you get started with Apollo Server quickly. This function is recommended for all projects that don't require serverless support or a particular Node.js framework (such as Fastify).
    +This `startStandaloneServer` function helps you get started with Apollo Server quickly.
    +This function is recommended for prototyping. For production services, we recommend integrating Apollo Server with a more fully-featured web framework such as Express, Koa, or Fastify.
     
    -Because it sets helpful defaults, this function is less configurable than other Apollo Server integrations. Complex projects might eventually need to [swap to using `expressMiddleware`](#swapping-to-expressmiddleware) (this process is straightforward).
    +You can find a list of supported web frameworks in [web framework integrations](../integrations/integration-index).
    +For an example migration path, see [Swapping to `expressMiddleware`](#swapping-to-expressmiddleware).
     
     ## `startStandaloneServer`
     
    @@ -191,12 +193,36 @@ const server = new ApolloServer<MyContext>({
     // Ensure we wait for our server to start
     await server.start();
     
    +// according to RFC8259, only UTF-8 is allowed in JSON text
    +// (see https://datatracker.ietf.org/doc/html/rfc8259#section-8.1)
    +// RFC 7159 also specifies that JSON could be UTF-16 or UTF-32,
    +// so we allow for that, too
    +const validCharset = /^utf-(8|((16|32)(le|be)?))$/i;
    +
     // Set up our Express middleware to handle CORS, body parsing,
     // and our expressMiddleware function.
     app.use('/',
       cors<cors.CorsRequest>(),
    -  // 50mb is the limit that `startStandaloneServer` uses, but you may configure this to suit your needs
    -  express.json({ limit: '50mb' }),
    +  express.json({
    +    verify(req) {
    +      const charset = parseContentType(req).parameters.charset || 'utf-8';
    +      if (!charset.match(validCharset)) {
    +        throw Object.assign(
    +          new Error(`unsupported charset "${charset.toUpperCase()}"`),
    +          {
    +            status: 415,
    +            name: 'UnsupportedMediaTypeError',
    +            charset,
    +            type: 'charset.unsupported',
    +          },
    +        );
    +      }
    +    },
    +    // 50mb is the limit that `startStandaloneServer` uses to cover all possible bases, but you may configure this to suit your needs.
    +    // Generally we recommend keeping this as small as possible to still suit your use case.
    +    // The `body-parser` default is '100kb'.
    +    // limit: '50mb',
    +  }),
       // expressMiddleware accepts the same arguments:
       // an Apollo Server instance and optional configuration options
       expressMiddleware(server, {
    
  • docs/source/getting-started.mdx+4 1 modified
    @@ -266,7 +266,10 @@ console.log(`🚀  Server ready at: ${url}`);
     
     </MultiCodeBlock>
     
    -> This tutorial uses Apollo Server's [standalone web server](./api/standalone). If you'd like to integrate Apollo Server with your favorite web framework such as Express, see our [web framework integrations](./integrations/integration-index).
    +> This tutorial uses Apollo Server's [standalone web server](./api/standalone).
    +> The standalone server is great for prototyping, but in the long run we recommend that you integrate Apollo Server with a more fully-featured web framework.
    +> You can find a list of supported web frameworks in [web framework integrations](./integrations/integration-index).
    +> This is not a choice you have to make now, as swapping from the standalone server to a web framework later is straightforward. For an example migration path, see [Swapping to `expressMiddleware`](./api/standalone#swapping-to-expressmiddleware).
     
     ## Step 7: Start the server
     
    
  • package.json+2 0 modified
    @@ -49,6 +49,7 @@
         "@rollup/plugin-commonjs": "28.0.6",
         "@types/async-retry": "1.4.9",
         "@types/body-parser": "1.19.6",
    +    "@types/content-type": "^1.1.9",
         "@types/cors": "2.8.19",
         "@types/express": "5.0.3",
         "@types/express-serve-static-core": "5.0.7",
    @@ -67,6 +68,7 @@
         "graphql": "16.11.0",
         "graphql-subscriptions": "3.0.0",
         "graphql-tag": "2.12.6",
    +    "iconv-lite": "^0.7.2",
         "jest": "30.0.5",
         "jest-config": "30.0.5",
         "jest-junit": "16.0.0",
    
  • package-lock.json+55 6 modified
    @@ -23,6 +23,7 @@
             "@rollup/plugin-commonjs": "28.0.6",
             "@types/async-retry": "1.4.9",
             "@types/body-parser": "1.19.6",
    +        "@types/content-type": "^1.1.9",
             "@types/cors": "2.8.19",
             "@types/express": "5.0.3",
             "@types/express-serve-static-core": "5.0.7",
    @@ -41,6 +42,7 @@
             "graphql": "16.11.0",
             "graphql-subscriptions": "3.0.0",
             "graphql-tag": "2.12.6",
    +        "iconv-lite": "^0.7.2",
             "jest": "30.0.5",
             "jest-config": "30.0.5",
             "jest-junit": "16.0.0",
    @@ -562,6 +564,7 @@
           "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.7.tgz",
           "integrity": "sha512-BU2f9tlKQ5CAthiMIgpzAh4eDTLWo1mqi9jqE2OxMG0E/OM199VJt2q8BztTxpnSW0i1ymdwLXRJnYzvDM5r2w==",
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "@ampproject/remapping": "^2.2.0",
             "@babel/code-frame": "^7.27.1",
    @@ -1536,7 +1539,8 @@
           "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.18.tgz",
           "integrity": "sha512-EF77RqROHL+4LhMGW5NTeKqfUd/e4OOv6EDFQ/UQQiFyWuqkEKyEz0NDILxOFxWUEVdjT2GQ2cC7t12B6pESwg==",
           "dev": true,
    -      "license": "MIT"
    +      "license": "MIT",
    +      "peer": true
         },
         "node_modules/@cspell/dict-dart": {
           "version": "2.3.1",
    @@ -1676,14 +1680,16 @@
           "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.12.tgz",
           "integrity": "sha512-JFffQ1dDVEyJq6tCDWv0r/RqkdSnV43P2F/3jJ9rwLgdsOIXwQbXrz6QDlvQLVvNSnORH9KjDtenFTGDyzfCaA==",
           "dev": true,
    -      "license": "MIT"
    +      "license": "MIT",
    +      "peer": true
         },
         "node_modules/@cspell/dict-html-symbol-entities": {
           "version": "4.0.4",
           "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.4.tgz",
           "integrity": "sha512-afea+0rGPDeOV9gdO06UW183Qg6wRhWVkgCFwiO3bDupAoyXRuvupbb5nUyqSTsLXIKL8u8uXQlJ9pkz07oVXw==",
           "dev": true,
    -      "license": "MIT"
    +      "license": "MIT",
    +      "peer": true
         },
         "node_modules/@cspell/dict-java": {
           "version": "5.0.12",
    @@ -1881,7 +1887,8 @@
           "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz",
           "integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==",
           "dev": true,
    -      "license": "MIT"
    +      "license": "MIT",
    +      "peer": true
         },
         "node_modules/@cspell/dict-vue": {
           "version": "3.0.5",
    @@ -3400,6 +3407,7 @@
           "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.0.5.tgz",
           "integrity": "sha512-7oEJT19WW4oe6HR7oLRvHxwlJk2gev0U9px3ufs8sX9PoD1Eza68KF0/tlN7X0dq/WVsBScXQGgCldA1V9Y/jA==",
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "@jest/environment": "30.0.5",
             "@jest/expect": "30.0.5",
    @@ -3932,6 +3940,7 @@
           "version": "4.0.2",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "engines": {
             "node": ">=12"
           },
    @@ -4369,6 +4378,13 @@
             "@types/node": "*"
           }
         },
    +    "node_modules/@types/content-type": {
    +      "version": "1.1.9",
    +      "resolved": "https://registry.npmjs.org/@types/content-type/-/content-type-1.1.9.tgz",
    +      "integrity": "sha512-Hq9IMnfekuOCsEmYl4QX2HBrT+XsfXiupfrLLY8Dcf3Puf4BkBOxSbWYTITSOQAhJoYPBez+b4MJRpIYL65z8A==",
    +      "dev": true,
    +      "license": "MIT"
    +    },
         "node_modules/@types/cookiejar": {
           "version": "2.1.5",
           "dev": true,
    @@ -4678,6 +4694,7 @@
           "integrity": "sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "@typescript-eslint/scope-manager": "8.40.0",
             "@typescript-eslint/types": "8.40.0",
    @@ -5304,6 +5321,7 @@
           "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "bin": {
             "acorn": "bin/acorn"
           },
    @@ -5900,6 +5918,7 @@
             }
           ],
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "caniuse-lite": "^1.0.30001716",
             "electron-to-chromium": "^1.5.149",
    @@ -6487,6 +6506,8 @@
         },
         "node_modules/content-type": {
           "version": "1.0.5",
    +      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
    +      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
           "license": "MIT",
           "engines": {
             "node": ">= 0.6"
    @@ -7424,6 +7445,7 @@
           "integrity": "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "@eslint-community/eslint-utils": "^4.2.0",
             "@eslint-community/regexpp": "^4.12.1",
    @@ -7986,6 +8008,19 @@
             "node": ">=4"
           }
         },
    +    "node_modules/external-editor/node_modules/iconv-lite": {
    +      "version": "0.4.24",
    +      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
    +      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
    +      "dev": true,
    +      "license": "MIT",
    +      "dependencies": {
    +        "safer-buffer": ">= 2.1.2 < 3"
    +      },
    +      "engines": {
    +        "node": ">=0.10.0"
    +      }
    +    },
         "node_modules/extract-files": {
           "version": "11.0.0",
           "dev": true,
    @@ -8593,6 +8628,7 @@
         "node_modules/graphql": {
           "version": "16.11.0",
           "license": "MIT",
    +      "peer": true,
           "engines": {
             "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
           }
    @@ -8689,6 +8725,7 @@
           "version": "5.14.0",
           "devOptional": true,
           "license": "MIT",
    +      "peer": true,
           "workspaces": [
             "website"
           ],
    @@ -8928,14 +8965,20 @@
           }
         },
         "node_modules/iconv-lite": {
    -      "version": "0.4.24",
    +      "version": "0.7.2",
    +      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
    +      "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "safer-buffer": ">= 2.1.2 < 3"
    +        "safer-buffer": ">= 2.1.2 < 3.0.0"
           },
           "engines": {
             "node": ">=0.10.0"
    +      },
    +      "funding": {
    +        "type": "opencollective",
    +        "url": "https://opencollective.com/express"
           }
         },
         "node_modules/ieee754": {
    @@ -9751,6 +9794,7 @@
           "resolved": "https://registry.npmjs.org/jest/-/jest-30.0.5.tgz",
           "integrity": "sha512-y2mfcJywuTUkvLm2Lp1/pFX8kTgMO5yyQGq/Sk/n2mN7XWYp4JsCZ/QXW34M8YScgk8bPZlREH04f6blPnoHnQ==",
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "@jest/core": "30.0.5",
             "@jest/types": "30.0.5",
    @@ -12802,6 +12846,7 @@
           "integrity": "sha512-BXHRqK1vyt9XVSEHZ9y7xdYtuYbwVod2mLwOMFP7t/Eqoc1pHRlG/WdV2qNeNvZHRQdLedaFycljaYYM96RqJQ==",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "dependencies": {
             "@types/estree": "1.0.8"
           },
    @@ -13838,6 +13883,7 @@
           "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "engines": {
             "node": ">=12"
           },
    @@ -14167,6 +14213,7 @@
           "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
           "dev": true,
           "license": "Apache-2.0",
    +      "peer": true,
           "bin": {
             "tsc": "bin/tsc",
             "tsserver": "bin/tsserver"
    @@ -14693,6 +14740,7 @@
           "version": "8.13.0",
           "dev": true,
           "license": "MIT",
    +      "peer": true,
           "engines": {
             "node": ">=10.0.0"
           },
    @@ -14961,6 +15009,7 @@
             "@graphql-tools/schema": "^10.0.0",
             "async-retry": "^1.2.1",
             "body-parser": "^2.2.2",
    +        "content-type": "^1.0.5",
             "cors": "^2.8.5",
             "finalhandler": "^2.1.0",
             "loglevel": "^1.6.8",
    
  • packages/server/package.json+1 0 modified
    @@ -138,6 +138,7 @@
         "@graphql-tools/schema": "^10.0.0",
         "async-retry": "^1.2.1",
         "body-parser": "^2.2.2",
    +    "content-type": "^1.0.5",
         "cors": "^2.8.5",
         "finalhandler": "^2.1.0",
         "loglevel": "^1.6.8",
    
  • packages/server/src/standalone/index.ts+24 1 modified
    @@ -1,6 +1,7 @@
     import type { WithRequired } from '@apollo/utils.withrequired';
     import cors from 'cors';
     import bodyParser from 'body-parser';
    +import { parse as parseContentType } from 'content-type';
     import http, { type IncomingMessage, type ServerResponse } from 'http';
     import type { ListenOptions } from 'net';
     import { parse as urlParse } from 'url';
    @@ -27,6 +28,12 @@ export interface StartStandaloneServerOptions<TContext extends BaseContext> {
       >;
     }
     
    +// according to RFC8259, only UTF-8 is allowed in JSON text
    +// (see https://datatracker.ietf.org/doc/html/rfc8259#section-8.1)
    +// RFC 7159 also specifies that JSON could be UTF-16 or UTF-32,
    +// so we allow for that, too
    +const validCharset = /^utf-(8|((16|32)(le|be)?))$/i;
    +
     export async function startStandaloneServer(
       server: ApolloServer<BaseContext>,
       options?: StartStandaloneServerOptions<BaseContext> & {
    @@ -45,7 +52,23 @@ export async function startStandaloneServer<TContext extends BaseContext>(
     ): Promise<{ url: string }> {
       const context = options?.context ?? (async () => ({}) as TContext);
       const corsHandler = cors();
    -  const jsonHandler = bodyParser.json({ limit: '50mb' });
    +  const jsonHandler = bodyParser.json({
    +    verify(req) {
    +      const charset = parseContentType(req).parameters.charset || 'utf-8';
    +      if (!charset.match(validCharset)) {
    +        throw Object.assign(
    +          new Error(`unsupported charset "${charset.toUpperCase()}"`),
    +          {
    +            status: 415,
    +            name: 'UnsupportedMediaTypeError',
    +            charset,
    +            type: 'charset.unsupported',
    +          },
    +        );
    +      }
    +    },
    +    limit: '50mb',
    +  });
       const httpServer = http.createServer((req, res) => {
         const errorHandler = finalhandler(req, res, {
           // Use the same onerror as Express.
    
  • packages/server/src/__tests__/standalone/standaloneSpecific.test.ts+134 0 modified
    @@ -1,4 +1,5 @@
     import { describe, expect, it } from '@jest/globals';
    +import { encode } from 'iconv-lite';
     import { ApolloServer } from '../..';
     import { startStandaloneServer } from '../../standalone';
     
    @@ -147,4 +148,137 @@ describe('Configuration', () => {
     
         await server.stop();
       });
    +
    +  it.each<{ encoding: string; charset: string | null }>([
    +    { encoding: 'utf-8', charset: null },
    +    { encoding: 'utf-8', charset: 'UTF-8' },
    +    { encoding: 'utf-8', charset: 'utf-8' },
    +    { encoding: 'utf-16', charset: 'utf-16' },
    +    { encoding: 'utf-16le', charset: 'utf-16le' },
    +    { encoding: 'utf-16be', charset: 'utf-16be' },
    +    { encoding: 'utf-32', charset: 'utf-32' },
    +    { encoding: 'utf-32le', charset: 'utf-32le' },
    +    { encoding: 'utf-32be', charset: 'utf-32be' },
    +  ])(
    +    'allows $encoding in request body (passed in header: $charset)',
    +    async ({ encoding, charset }) => {
    +      const server = new ApolloServer({
    +        typeDefs: `type Query { hello(name: String!): String! }`,
    +        resolvers: {
    +          Query: {
    +            hello: (_, { name }) => `hello ${name}!`,
    +          },
    +        },
    +      });
    +      const { url } = await startStandaloneServer(server, {
    +        listen: { port: 0 },
    +      });
    +      const result = await fetch(url, {
    +        method: 'POST',
    +        headers: {
    +          'Content-Type': `application/json${charset ? `;charset=${charset}` : ''}`,
    +        },
    +        body: encode(
    +          JSON.stringify({
    +            query: `query($name: String!){hello(name: $name)}`,
    +            variables: { name: '👻' },
    +          }),
    +          encoding,
    +        ),
    +      });
    +
    +      expect(result.ok).toBe(true);
    +      expect(result.status).toBe(200);
    +      expect(await result.json()).toEqual({
    +        data: { hello: 'hello 👻!' },
    +      });
    +
    +      await server.stop();
    +    },
    +  );
    +
    +  it.each<{
    +    encoding: string;
    +    charset: string | null;
    +    status: number;
    +    expectedError: RegExp;
    +  }>([
    +    // exotic encodings
    +    {
    +      encoding: 'win1251',
    +      charset: 'win1251',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;WIN1251&quot;/,
    +    },
    +    {
    +      encoding: 'iso-8859-1',
    +      charset: 'iso-8859-1',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;ISO-8859-1&quot;/,
    +    },
    +    {
    +      encoding: 'windows936',
    +      charset: 'windows936',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;WINDOWS936&quot;/,
    +    },
    +    {
    +      encoding: 'utf-7',
    +      charset: 'utf-7',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;UTF-7&quot;/,
    +    },
    +    {
    +      encoding: 'utf-7-imap',
    +      charset: 'utf-7-imap',
    +      status: 415,
    +      expectedError:
    +        /UnsupportedMediaTypeError: unsupported charset &quot;UTF-7-IMAP&quot;/,
    +    },
    +    // sending one encoding but declaring another
    +    {
    +      encoding: 'utf-7',
    +      charset: 'utf-8',
    +      status: 400,
    +      expectedError: /SyntaxError: Unexpected token .* is not valid JSON/,
    +    },
    +  ])(
    +    'fails with $status for $encoding in request body (passed in header: $charset)',
    +    async ({ encoding, charset, expectedError, status }) => {
    +      const server = new ApolloServer({
    +        typeDefs: `type Query { hello(name: String!): String! }`,
    +        resolvers: {
    +          Query: {
    +            hello: (_, { name }) => `hello ${name}!`,
    +          },
    +        },
    +      });
    +      const { url } = await startStandaloneServer(server, {
    +        listen: { port: 0 },
    +      });
    +      const result = await fetch(url, {
    +        method: 'POST',
    +        headers: {
    +          'Content-Type': `application/json${charset ? `;charset=${charset}` : ''}`,
    +        },
    +        body: encode(
    +          JSON.stringify({
    +            query: `query($name: String!){hello(name: $name)}`,
    +            variables: { name: '👻' },
    +          }),
    +          encoding,
    +        ),
    +      });
    +
    +      expect(result.ok).toBe(false);
    +      expect(result.status).toBe(status);
    +      expect(await result.text()).toMatch(expectedError);
    +
    +      await server.stop();
    +    },
    +  );
     });
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.