Vulnerabilities in pkg:npm/@envelop/graphql-modules

PACKAGE
Advisory Summary

GHSA-h3hw-29fv-2x75 is a HIGH @envelop/graphql-modules has a race condition vulnerability (CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')) affecting @envelop/graphql modules libraries in the npm ecosystem. The issue involves @envelop/graphql-modules has a race condition vulnerability. Remediation is available by upgrading affected packages to version 9.1.0.

1 Known Advisory Record(s)
Package Vulnerability Intelligence

pkg:npm/@envelop/graphql-modules

1 Known Advisory Record(s)

Vulnerability advisories affecting package pkg:npm/@envelop/graphql-modules. Select an advisory below to view technical details or fixes.

Advisory ID CVE / NVD Severity Summary
GHSA-h3hw-29fv-2x75 - HIGH @envelop/graphql-modules has a Race Condition vulnerability

GHSA-h3hw-29fv-2x75 at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-h3hw-29fv-2x75
Severity HIGH
CVSS v3.1 Base Score N/A
CWE Classification CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
Affected Product @envelop/graphql modules
Package Ecosystem npm
Published Date
Last Updated

How to Fix GHSA-h3hw-29fv-2x75

To remediate this vulnerability, upgrade all affected @envelop/graphql modules dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

@envelop/graphql-modules fixed: 9.1.0
npm install @envelop/graphql-modules@9.1.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls @envelop/graphql-modules

How to Check if You Are Affected

To determine whether your Node.js application is affected by GHSA-h3hw-29fv-2x75, inspect your project dependencies using npm:

npm ls @envelop/graphql-modules

Analyze the terminal output to locate any version of @envelop/graphql modules in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 9.1.0), your application is affected.

Note: The npm ls @envelop/graphql-modules command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition'), where the product contains a concurrent code sequence that requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence operating concurrently. In @envelop/graphql modules, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary Context race condition when using `useGraphQLModules` plugin ### Details Related to: https://github.com/graphql-hive/graphql-modules/security/advisories/GHSA-53wg-r69p-v3r7 When 2 or more parallel requests are made which trigger the same service, the context of the requests is mixed up in the service when the context is injected via @ExecutionContext() and graphql-modules are used in Yoga with `useGraphQLModules(application)`. This issue was fixed in `graphql-modules` in `2.4.1` and `3.1.1` but using `useGraphQLModules` will bypass the `async_hooks` fix that was implemented. ### PoC Create the following `package.json` and run `npm i` ```json { "name": "poc", "scripts": { "compile": "tsc", "start": "npm run compile && node ./dist/src/index.js", "test": "npm run compile && node ./dist/test/bleedtest.js" }, "dependencies": { "@envelop/graphql-modules": "^9.0.0", "graphql-yoga": "^5.0.0", "graphql": "^16.10.0", "graphql-modules": "3.1.1", "reflect-metadata": "0.2.1", "axios": "^1.8.4" }, "devDependencies": { "@types/node": "^22.14.1", "typescript": "^5.8.3" } } ``` Define the app entrypoint: `src/index.ts` ```ts import { module } from "./module.js"; import { useGraphQLModules } from '@envelop/graphql-modules' import { createApplication } from "graphql-modules"; import { createServer } from 'node:http' import { randomUUID } from "node:crypto"; import { createYoga } from 'graphql-yoga'; const application = createApplication({ modules: [module] }) const yoga = createYoga({ schema: application.schema, plugins: [useGraphQLModules(application)], context() { return { requestId: randomUUID(), } } }) const server = createServer(yoga) server.listen(4001, '127.0.0.1', undefined, () => { console.info( `[Server] Running on http://localhost:4001/graphql` ) }) ``` Create the test module: `src/module.ts` ```ts import { createModule, gql } from "graphql-modules"; import Service from "./service.js"; const typeDefs = gql` type Book { id1: String id2: String } type Query { books: [Book] } `; export const module = createModule({ id: 'book-module', typeDefs: [typeDefs], providers: [Service], resolvers: { Query: { // return one empty book books: () => [{}], }, Book: { // return the requestId from the context id1: async (_root, _args, { injector } ) => { return injector.get(Service).get(); }, // return the requestId from the context of the service 100 ms later id2: async (_root, _args, { injector } ) => { await new Promise(resolve => setTimeout(resolve, 100)); return injector.get(Service).get() }, } } }) ``` Add the Service that's to be injected `src/service.ts` ```ts import { ExecutionContext, Injectable } from 'graphql-modules'; import 'reflect-metadata'; @Injectable() export default class Service { @ExecutionContext() private context: ExecutionContext; get() { return this.context.requestId; } } ``` Add the test case `test/bleedtest.js` ```ts import axios from 'axios'; const url = 'http://localhost:4001/graphql'; const query = `query { books { id1 id2 } }`; const makeGraphQLRequest = async () => { const response = await axios.post(url, { query }); const book = response.data.data.books[0] if (book.id1 !== book.id2) { throw new Error(`wrong response with ids ${(book.id1)} and ${(book.id2)}`) } } const numberOfRequests = 2; await Promise.all(Array.from( { length: numberOfRequests }, makeGraphQLRequest, )); ``` Then run the server with `npm run start` in one terminal and the testcase in another with `npm run test`. The returned IDs should be identical as they are both read from the context within the same request. However, there is a mismatch: ``` ❯ npm run test > poc@1.0.0 test > npm run compile && node ./dist/test/bleedtest.js > poc@1.0.0 compile > tsc file://<redacted>/dist/test/bleedtest.js:8 throw new Error(`wrong response with ids ${(book.id1)} and ${(book.id2)}`); ^ Error: wrong response with ids c2d83151-0922-4f25-a3e9-2f03acc1376a and e16c7335-0eaa-4386-b415-869ee4b05315 at makeGraphQLRequest (file://<redacted>/dist/test/bleedtest.js:8:15) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async Promise.all (index 0) at async file://<redacted>/dist/test/bleedtest.js:12:1 ``` ### Impact Any application that uses `useGraphQLModules` from `@envelop/graphql-modules` along with services that inject the context using @ExecutionContext() from a singleton provider are at risk. The more traffic an application has, the higher the chance for parallel requests, the higher the risk.

GHSA-h3hw-29fv-2x75 Affected @envelop/graphql modules Versions

1 component(s)
Fixed Versions:
9.1.0
Product / Package Ecosystem Affected Versions Fixed Version
@envelop/graphql-modules
npm
< 9.1.0
9.1.0

References

Frequently Asked Questions

What is GHSA-h3hw-29fv-2x75?
GHSA-h3hw-29fv-2x75 is a security vulnerability in @envelop/graphql modules involving @envelop/graphql-modules has a Race Condition vulnerability under CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition').
Which @envelop/graphql modules versions are affected?
Affected versions include releases prior to 9.1.0 across affected packages: @envelop/graphql-modules.
What version fixes GHSA-h3hw-29fv-2x75?
Upgrading to 9.1.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is @envelop/graphql-modules affected?
Yes, @envelop/graphql-modules is affected in releases prior to 9.1.0. Upgrade your dependency to 9.1.0 or later.
What CWE is associated with GHSA-h3hw-29fv-2x75?
GHSA-h3hw-29fv-2x75 is classified under CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') (The product contains a concurrent code sequence that requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence operating concurrently.).
How can I check npm dependencies for GHSA-h3hw-29fv-2x75?
Run the dependency tree command: 'npm ls @envelop/graphql-modules'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-h3hw-29fv-2x75",
  "modified" : "2026-01-29T03:50:11Z",
  "published" : "2026-01-21T16:36:27Z",
  "aliases" : [ ],
  "summary" : "@envelop/graphql-modules has a Race Condition vulnerability",
  "details" : "### Summary\nContext race condition when using `useGraphQLModules` plugin\n\n### Details\n\nRelated to: https://github.com/graphql-hive/graphql-modules/security/advisories/GHSA-53wg-r69p-v3r7\n\nWhen 2 or more parallel requests are made which trigger the same service, the context of the requests is mixed up in the service when the context is injected via @ExecutionContext() and graphql-modules are used in Yoga with `useGraphQLModules(application)`. This issue was fixed in `graphql-modules` in `2.4.1` and `3.1.1` but using `useGraphQLModules` will bypass the `async_hooks` fix that was implemented.\n\n### PoC\n\nCreate the following `package.json` and run `npm i`\n\n```json\n{\n  \"name\": \"poc\",\n  \"scripts\": {\n    \"compile\": \"tsc\",\n    \"start\": \"npm run compile && node ./dist/src/index.js\",\n    \"test\": \"npm run compile && node ./dist/test/bleedtest.js\"\n  },\n  \"dependencies\": {\n    \"@envelop/graphql-modules\": \"^9.0.0\",\n    \"graphql-yoga\": \"^5.0.0\",\n    \"graphql\": \"^16.10.0\",\n    \"graphql-modules\": \"3.1.1\",\n    \"reflect-metadata\": \"0.2.1\",\n    \"axios\": \"^1.8.4\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.14.1\",\n    \"typescript\": \"^5.8.3\"\n  }\n}\n```\n\nDefine the app entrypoint: `src/index.ts`\n\n```ts\nimport { module } from \"./module.js\";\nimport { useGraphQLModules } from '@envelop/graphql-modules'\nimport { createApplication } from \"graphql-modules\";\nimport { createServer } from 'node:http'\nimport { randomUUID } from \"node:crypto\";\nimport { createYoga } from 'graphql-yoga';\n\nconst application = createApplication({\n    modules: [module]\n})\n\nconst yoga = createYoga({\n    schema: application.schema,\n    plugins: [useGraphQLModules(application)],\n    context() {\n        return {\n            requestId: randomUUID(),\n        }\n    }\n})\n\nconst server = createServer(yoga)\nserver.listen(4001, '127.0.0.1', undefined, () => {\n    console.info(\n        `[Server] Running on http://localhost:4001/graphql`\n    )\n})\n```\n\nCreate the test module: `src/module.ts`\n\n```ts\nimport { createModule, gql } from \"graphql-modules\";\nimport Service from \"./service.js\";\n\nconst typeDefs = gql`\n    type Book {\n        id1: String\n        id2: String\n    }\n    type Query {\n        books: [Book]\n    }\n`;\n\nexport const module = createModule({\n    id: 'book-module',\n    typeDefs: [typeDefs],\n    providers: [Service],\n    resolvers: {\n        Query: {\n            // return one empty book\n            books: () => [{}],\n        },\n        Book: {\n            // return the requestId from the context\n            id1: async (_root, _args, { injector } ) => {\n                return injector.get(Service).get();\n            },\n            // return the requestId from the context of the service 100 ms later\n            id2: async (_root, _args, { injector } ) => {\n                await new Promise(resolve => setTimeout(resolve, 100));\n                return injector.get(Service).get()\n            },\n        }\n    }\n})\n```\n\nAdd the Service that's to be injected `src/service.ts`\n\n```ts\nimport { ExecutionContext, Injectable } from 'graphql-modules';\nimport 'reflect-metadata';\n\n@Injectable()\nexport default class Service {\n    @ExecutionContext()\n    private context: ExecutionContext;\n\n    get() {\n        return this.context.requestId;\n    }\n}\n```\n\nAdd the test case `test/bleedtest.js`\n\n```ts\nimport axios from 'axios';\n\nconst url = 'http://localhost:4001/graphql';\nconst query = `query { books { id1 id2 } }`;\n\nconst makeGraphQLRequest = async () => {\n    const response = await axios.post(url, { query });\n\n    const book = response.data.data.books[0]\n    if (book.id1 !== book.id2) {\n        throw new Error(`wrong response with ids ${(book.id1)} and ${(book.id2)}`)\n    }\n}\n\nconst numberOfRequests = 2;\nawait Promise.all(Array.from(\n    { length: numberOfRequests },\n    makeGraphQLRequest,\n));\n```\n\nThen run the server with `npm run start` in one terminal and the testcase in another with `npm run test`.\nThe returned IDs should be identical as they are both read from the context within the same request.\nHowever, there is a mismatch:\n\n```\n❯ npm run test\n\n> poc@1.0.0 test\n> npm run compile && node ./dist/test/bleedtest.js\n\n\n> poc@1.0.0 compile\n> tsc\n\nfile://<redacted>/dist/test/bleedtest.js:8\n        throw new Error(`wrong response with ids ${(book.id1)} and ${(book.id2)}`);\n              ^\n\nError: wrong response with ids c2d83151-0922-4f25-a3e9-2f03acc1376a and e16c7335-0eaa-4386-b415-869ee4b05315\n    at makeGraphQLRequest (file://<redacted>/dist/test/bleedtest.js:8:15)\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n    at async Promise.all (index 0)\n    at async file://<redacted>/dist/test/bleedtest.js:12:1\n```\n\n### Impact\nAny application that uses `useGraphQLModules` from `@envelop/graphql-modules` along with services that inject the context using @ExecutionContext() from a singleton provider are at risk. The more traffic an application has, the higher the chance for parallel requests, the higher the risk.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@envelop/graphql-modules"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "9.1.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/graphql-hive/envelop/security/advisories/GHSA-h3hw-29fv-2x75"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/graphql-hive/graphql-modules/security/advisories/GHSA-53wg-r69p-v3r7"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/graphql-hive/envelop/commit/ab49fa259a51d976c437e084114e070b99720ba9"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/graphql-hive/envelop"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/graphql-hive/envelop/releases/tag/release-1768928934700"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-362" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-01-21T16:36:27Z",
    "nvd_published_at" : null
  }
}