Skip to main content
VulnerabilityPublished

CVE-2026-118665: GraphQL Tools · Per-request connection parameters persist into later users' WebSocket authentications

Affects @graphql-tools/executor-legacy-wsSource GCVE Database

0
Authoritative record:CVE-2026-118665· High 8.2

Not known to be exploited · CVSS 8.2 High : upgrade to 1.1.36 soon.

Data as of 28 Oct 2026, 22:12 UTC

CVSS 4.0 base score
8.2High
How severe the flaw is on the 0–10 CVSS scale.
Patch
Available – fixed in 1.1.36
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N

Exploitation evidence

  1. Disclosed: evidence found.

    CVE published 28 Oct 2026

  2. Detectable: no evidence on record.

    No public nuclei template indexed

  3. Weaponised: no evidence on record.

    No public exploit code indexed in Metasploit or Exploit-DB

  4. Exploited in the wild: no evidence on record.

    Not in CISA KEV and no source reports exploitation

  5. Observed by OffSeq Mirage: no evidence on record.

    No attack traffic recorded by OffSeq Mirage sensors

A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 26 Oct 2026.

What to do

Upgrade @graphql-tools/executor-legacy-ws to 1.1.36.

Affected software

ProductAffectedFixed in
npm@graphql-tools/executor-legacy-wsAffected
  • <1.1.36
Fixed in
  • 1.1.36

Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.

Description

# Stale authentication state in `@graphql-tools/executor-legacy-ws`: per-request `extensions.connectionParams` persist in executor closure state and are replayed in a later caller's `connection_init` ## Report metadata | Field | Value | | --- | --- | | Package | `@graphql-tools/executor-legacy-ws` (npm, `pkg:npm/%40graphql-tools/executor-legacy-ws`) | | Repository | https://github.com/ardatan/graphql-tools | | Component | `buildWSLegacyExecutor` (`packages/executors/legacy-ws/src/index.ts`) | | Vulnerability class | Stale authentication state / credential reuse across requests | | Verified against | Commit `b5d1c36ebb8ed3868260ffee5bbcbb423ad5c1f1`; npm release `1.1.33` installed and exercised. During validation the same behaviour was also observed on the current latest release `1.1.35`, and the unreset closure is still present on `master`. | | API surface | Public documented API (`buildWSLegacyExecutor`, and `request.extensions.connectionParams` on the returned executor) | | Affected in default configuration | Yes — the factory returns a general, reusable `Executor` with no per-identity or single-use restriction, and no supported teardown clears the retained parameters. | Version note: the originally recorded affected range was `<= 1.1.33`. Validation showed that range understates exposure — the same proof of concept leaks identically on `1.1.35`. ## Summary `buildWSLegacyExecutor` keeps a single closure-scoped object, `executorConnectionParams`, for the lifetime of the executor. Every execution that carries `request.extensions.connectionParams` merges those keys into that object with `Object.assign`, and the object is merged into the `connection_init` payload each time a new WebSocket opens. Nothing ever removes keys: `cleanupWebsocket` terminates the socket and nulls the handle but leaves `executorConnectionParams` intact, and a later request that simply omits a key skips the conditional update entirely. The consumer-side shape is a shared executor that forwards per-user credentials. When one long-lived executor serves multiple principals — the schema-stitching, gateway, or mesh pattern where each `ExecutionRequest` supplies its own `extensions.connectionParams` — a request that omits the auth key is sent to the downstream server with the previous caller's `Authorization`/tenant values in its `connection_init`, so the downstream server authenticates the later caller as the earlier user. Behaviour of the neighbouring state in the same file: - WebSocket handle (`websocket`) → reset on teardown in `cleanupWebsocket`, [lines 78-88](https://github.com/ardatan/graphql-tools/blob/b5d1c36ebb8ed3868260ffee5bbcbb423ad5c1f1/packages/executors/legacy-ws/src/index.ts#L78-L88) - Per-request `connectionParams` merge, present case → applied as documented, [lines 93-101](https://github.com/ardatan/graphql-tools/blob/b5d1c36ebb8ed3868260ffee5bbcbb423ad5c1f1/packages/executors/legacy-ws/src/index.ts#L93-L101) - `executorConnectionParams` closure object → **never reset; survives socket teardown and is re-sent on the next connection, [line 32](https://github.com/ardatan/graphql-tools/blob/b5d1c36ebb8ed3868260ffee5bbcbb423ad5c1f1/packages/executors/legacy-ws/src/index.ts#L32) and [line 54](https://github.com/ardatan/graphql-tools/blob/b5d1c36ebb8ed3868260ffee5bbcbb423ad5c1f1/packages/executors/legacy-ws/src/index.ts#L54)** ## Impact A caller who supplies no credentials (or lower-privileged ones) can have its downstream GraphQL subscription executed under a previous user's retained token or tenant value, and can receive data that its own `connection_init` would not authorize. The credential itself is never disclosed to the attacker — it reaches the sink through closure storage, not because the attacker knows it — but the downstream authorization it represents is. The new capability versus safe behaviour: without this bug, an anonymous request would open a connection whose `connection_init` contains only base options plus that request's own parameters, and the downstream server would treat it as anonymous. With it, the anonymous request inherits the victim's authorization. Validation also showed partial-overwrite merging: a later caller supplying only `{tenant: "<attacker tenant>"}` gets the victim's `Authorization` retained alongside its own tenant, i.e. an attacker-chosen tenant authenticated with someone else's bearer token. Scoring note: **not scored.** No CVSS vector accompanies this finding, and exploitability depends on the consuming application's data flow rather than on the library alone. Consumers that construct a fresh executor per request are **not** affected — the in-repository `UrlLoader` wrapper ([`packages/loaders/url/src/index.ts:172-182`](https://github.com/ardatan/graphql-tools/blob/b5d1c36ebb8ed3868260ffee5bbcbb423ad5c1f1/packages/loaders/url/src/index.ts#L172-L182)) builds a new executor for each request and therefore does not exhibit the persistence. The exposure is to applications that use the

References

Community reviews

Loading reviews…