CVE-2026-102281: Nest Remote Process Termination Vulnerability

HIGH
Advisory Identifier: GHSA-m8vh-jmq9-5rjg
CVSS 7.5
CWE-674 CWE-248
Published
Advisory Summary

CVE-2026-102281 is a HIGH (CVSS 7.5) remote process termination vulnerability (CWE-674: Uncontrolled Recursion) affecting Nest libraries in the npm ecosystem. The issue involves remote process termination via a deeply nested microservice message pattern. Remediation is available by upgrading affected packages to version 11.2.4, 12.0.2.

CVE-2026-102281 at a Glance

CVE Identifier CVE-2026-102281
GHSA Identifier GHSA-m8vh-jmq9-5rjg
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-674: Uncontrolled Recursion
Affected Product Nest
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 7.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity None (I:N)
Availability High (A:H)

How to Fix CVE-2026-102281

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

@nestjs/microservices fixed: 11.2.4
npm install @nestjs/microservices@11.2.4
@nestjs/microservices fixed: 12.0.2
npm install @nestjs/microservices@12.0.2
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 @nestjs/microservices

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-102281, inspect your project dependencies using npm:

npm ls @nestjs/microservices

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

Note: The npm ls @nestjs/microservices 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-674: Uncontrolled Recursion, where the product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack. In Nest, 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

| Field | Value | | --- | --- | | Ecosystem | npm | | Package | `@nestjs/microservices` | | Affected versions | `>= 12.0.0, < 12.0.2` and `< 11.2.4` | | Patched versions | `12.0.2` and `11.2.4` (upgrade to `12.0.3` / `11.2.5`) | ### Summary A single message whose `pattern` is a deeply nested object terminates a NestJS microservice that uses the TCP or RabbitMQ transport. The server serialized the client-supplied pattern with `JSON.stringify` to derive the handler lookup key; on deeply nested input this throws `RangeError: Maximum call stack size exceeded`. The exception escaped the asynchronous message handler as an unhandled promise rejection, which terminates the Node.js process under the default `--unhandled-rejections=throw`. ### Impact Denial of service, one message per crash, repeatable. The attacker needs to be able to reach the transport: connect to the TCP transport's port, or publish to the queue or exchange the service consumes from. The TCP transport performs no authentication by default, so on a reachable port this requires nothing else. Only the **TCP** and **RabbitMQ** transports are affected. The other transports take the pattern as a string from the broker topic or channel and never serialize a client-supplied object to build it. ### Details In `ServerTCP#handleMessage` and `ServerRMQ#handleMessage` the pattern was stringified without a guard: ```ts const pattern = isString(packet.pattern) ? packet.pattern : JSON.stringify(packet.pattern); ``` `JSON.parse` accepts nesting depths that `JSON.stringify` cannot re-serialize, because `JSON.stringify` recurses natively, so an attacker can craft a payload that parses successfully on arrival and then throws when the pattern is converted back to a string. Neither transport attached a rejection handler to the promise returned by `handleMessage`, so the `RangeError` propagated out as an unhandled rejection. ### Proof of concept Against a NestJS microservice on the TCP transport (default port 3001). The nested JSON is built as text rather than with `JSON.stringify`, which is what makes the payload serializable by the attacker but not by the victim: ```js const { connect } = require('node:net'); const DEPTH = 100_000; const pattern = '{"nested":'.repeat(DEPTH) + '{}' + '}'.repeat(DEPTH); const payload = `{"pattern":${pattern},"data":null,"id":"1"}`; const socket = connect(3001, '127.0.0.1', () => { // Nest's TCP framing is <byteLength>#<json> socket.write(`${Buffer.byteLength(payload)}#${payload}`); }); ``` The service exits with `RangeError: Maximum call stack size exceeded`. The equivalent payload published to the consumed queue crashes a RabbitMQ-transport service. ### Patches Fixed in **12.0.2** and **11.2.4**. - Incoming patterns are converted through a guarded `Server#getPatternAsString`, which falls back to a sentinel value that matches no handler. Such a message now receives the ordinary "no message handler" response (TCP) or is negatively acknowledged (RabbitMQ) instead of crashing the process. - Rejections escaping `handleMessage` in both transports are routed to `handleError` rather than left unhandled. ### Workarounds If you cannot upgrade, restrict network access to the transport so that only trusted peers can reach it. Running the process with `--unhandled-rejections=warn` prevents the crash but leaves the message unprocessed and is not a substitute for the fix. ### Credit Reported by ZeroVuln Labs.

CVE-2026-102281 Affected Nest Versions

2 component(s)
Fixed Versions:
11.2.412.0.2
Product / Package Ecosystem Affected Versions Fixed Version
@nestjs/microservices
npm
< 11.2.4
11.2.4
@nestjs/microservices
npm
≥ 12.0.0
< 12.0.2
12.0.2

References

Frequently Asked Questions

What is CVE-2026-102281?
CVE-2026-102281 is a security vulnerability in Nest involving Remote process termination via a deeply nested microservice message pattern under CWE-674: Uncontrolled Recursion.
Which Nest versions are affected?
Affected versions include releases prior to 11.2.4, 12.0.2 across affected packages: @nestjs/microservices.
What version fixes CVE-2026-102281?
Upgrading to 11.2.4, 12.0.2 (or the latest patched release for your respective branch) resolves the vulnerability.
Is @nestjs/microservices affected?
Yes, @nestjs/microservices is affected in releases prior to 11.2.4, 12.0.2. Upgrade your dependency to 11.2.4, 12.0.2 or later.
What is the CVSS score of CVE-2026-102281?
CVE-2026-102281 has a CVSS v3.1 base score of 7.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.
What CWE is associated with CVE-2026-102281?
CVE-2026-102281 is classified under CWE-674: Uncontrolled Recursion (The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack.).
How can I check npm dependencies for CVE-2026-102281?
Run the dependency tree command: 'npm ls @nestjs/microservices'. 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-m8vh-jmq9-5rjg",
  "modified" : "2026-09-29T23:54:44Z",
  "published" : "2026-09-29T23:54:44Z",
  "aliases" : [ "CVE-2026-102281" ],
  "summary" : "Nest: Remote process termination via a deeply nested microservice message pattern",
  "details" : "| Field | Value |\n| --- | --- |\n| Ecosystem | npm |\n| Package | `@nestjs/microservices` |\n| Affected versions | `>= 12.0.0, < 12.0.2` and `< 11.2.4` |\n| Patched versions | `12.0.2` and `11.2.4` (upgrade to `12.0.3` / `11.2.5`) |\n\n### Summary\n\nA single message whose `pattern` is a deeply nested object terminates a NestJS microservice that uses the TCP or\nRabbitMQ transport. The server serialized the client-supplied pattern with `JSON.stringify` to derive the handler\nlookup key; on deeply nested input this throws `RangeError: Maximum call stack size exceeded`. The exception escaped\nthe asynchronous message handler as an unhandled promise rejection, which terminates the Node.js process under the\ndefault `--unhandled-rejections=throw`.\n\n### Impact\n\nDenial of service, one message per crash, repeatable. The attacker needs to be able to reach the transport: connect\nto the TCP transport's port, or publish to the queue or exchange the service consumes from. The TCP transport\nperforms no authentication by default, so on a reachable port this requires nothing else.\n\nOnly the **TCP** and **RabbitMQ** transports are affected. The other transports take the pattern as a string from the\nbroker topic or channel and never serialize a client-supplied object to build it.\n\n### Details\n\nIn `ServerTCP#handleMessage` and `ServerRMQ#handleMessage` the pattern was stringified without a guard:\n\n```ts\nconst pattern = isString(packet.pattern)\n  ? packet.pattern\n  : JSON.stringify(packet.pattern);\n```\n\n`JSON.parse` accepts nesting depths that `JSON.stringify` cannot re-serialize, because `JSON.stringify` recurses\nnatively, so an attacker can craft a payload that parses successfully on arrival and then throws when the pattern is\nconverted back to a string. Neither transport attached a rejection handler to the promise returned by\n`handleMessage`, so the `RangeError` propagated out as an unhandled rejection.\n\n### Proof of concept\n\nAgainst a NestJS microservice on the TCP transport (default port 3001). The nested JSON is built as text rather than\nwith `JSON.stringify`, which is what makes the payload serializable by the attacker but not by the victim:\n\n```js\nconst { connect } = require('node:net');\n\nconst DEPTH = 100_000;\nconst pattern = '{\"nested\":'.repeat(DEPTH) + '{}' + '}'.repeat(DEPTH);\nconst payload = `{\"pattern\":${pattern},\"data\":null,\"id\":\"1\"}`;\n\nconst socket = connect(3001, '127.0.0.1', () => {\n  // Nest's TCP framing is <byteLength>#<json>\n  socket.write(`${Buffer.byteLength(payload)}#${payload}`);\n});\n```\n\nThe service exits with `RangeError: Maximum call stack size exceeded`. The equivalent payload published to the\nconsumed queue crashes a RabbitMQ-transport service.\n\n### Patches\n\nFixed in **12.0.2** and **11.2.4**.\n\n- Incoming patterns are converted through a guarded `Server#getPatternAsString`, which falls back to a sentinel value\n  that matches no handler. Such a message now receives the ordinary \"no message handler\" response (TCP) or is\n  negatively acknowledged (RabbitMQ) instead of crashing the process.\n- Rejections escaping `handleMessage` in both transports are routed to `handleError` rather than left unhandled.\n\n### Workarounds\n\nIf you cannot upgrade, restrict network access to the transport so that only trusted peers can reach it. Running the\nprocess with `--unhandled-rejections=warn` prevents the crash but leaves the message unprocessed and is not a\nsubstitute for the fix.\n\n### Credit\n\nReported by ZeroVuln Labs.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@nestjs/microservices"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "11.2.4"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@nestjs/microservices"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "12.0.0"
      }, {
        "fixed" : "12.0.2"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/nestjs/nest/security/advisories/GHSA-m8vh-jmq9-5rjg"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-102281"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nestjs/nest/pull/17737"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nestjs/nest/commit/aa97b5144d8dff1ce700aac521eb86449a679d6f"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nestjs/nest/commit/e9dcd4c7ac64361fbfe79461da85f5b3fc3e02da"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/nestjs/nest"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nestjs/nest/releases/tag/v11.2.4"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/nestjs/nest/releases/tag/v12.0.2"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-248", "CWE-674" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-29T23:54:44Z",
    "nvd_published_at" : "2026-09-28T22:17:32Z"
  }
}