---
id: "CVE-2026-102281"
page: "https://infrastack.ai/live/CVE-2026-102281"
kind: "vulnerability"
aliases: ["CVE-2026-102281", "GHSA-m8vh-jmq9-5rjg"]
title: "Nest: Remote process termination via a deeply nested microservice message pattern"
severity: "high"
cvss: 7.5
epss: 0.00586
exploited: false
status: "open"
category: "package"
products: [{"name": "@nestjs/microservices", "note": ">= 12.0.0, < 12.0.2 and < 11.2.4", "fixed": ["12.0.2 and 11.2.4"], "affected": ">= 12.0.0, < 12.0.2, < 11.2.4", "ecosystem": ""}, {"name": "@nestjs/microservices", "fixed": ["11.2.4"], "affected": "< 11.2.4", "ecosystem": "npm"}, {"name": "@nestjs/microservices", "fixed": ["12.0.2"], "affected": ">= 12.0.0, < 12.0.2", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["cwe-248", "cwe-674", "microservices", "nestjs", "node", "package", "rabbitmq", "tcp-transport"]
not_affected_if: ["other-transports", "private-network-only", "rabbitmq-auth-restricted"]
published_at: "2026-09-15T08:38:29+00:00"
first_seen_at: "2026-11-09T22:53:18+00:00"
updated_at: "2026-11-09T22:59:29+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/nestjs/nest/security/advisories/GHSA-m8vh-jmq9-5rjg", "first_seen_at": "2026-11-09T22:53:18+00:00"}, {"source": "ghsa", "url": "https://github.com/advisories/GHSA-m8vh-jmq9-5rjg", "first_seen_at": "2026-11-09T22:57:50+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-102281", "first_seen_at": "2026-11-09T23:10:12+00:00"}]
exploit_sources: [{"type": "epss", "score": 0.00586, "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-102281"}]
---

# Nest: Remote process termination via a deeply nested microservice message pattern

Link for people: https://infrastack.ai/live/CVE-2026-102281 (this .md is for agents)

A deeply nested object sent as the message pattern to a NestJS microservice using the TCP or RabbitMQ transport makes the server throw a stack overflow that escapes as an unhandled promise rejection. The Node.js process terminates, and an attacker can repeat this one message at a time to keep the service down.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- :@nestjs/microservices affected >= 12.0.0, < 12.0.2, < 11.2.4 fixed 12.0.2 and 11.2.4
- npm:@nestjs/microservices affected < 11.2.4 fixed 11.2.4
- npm:@nestjs/microservices affected >= 12.0.0, < 12.0.2 fixed 12.0.2

## How to check

- Check the installed version: `npm ls @nestjs/microservices`
- Confirm the transport: look for `Transport.TCP` or `Transport.RMQ` in the microservice bootstrap code
- Check whether the TCP port (default 3001) or the consumed RabbitMQ queue is reachable by untrusted peers

## Fix

- `@nestjs/microservices` 12.x: upgrade to `12.0.2` or later
- `@nestjs/microservices` 11.x: upgrade to `11.2.4` or later

## Timeline

- 2026-11-09T22:53:18+00:00 ghsa-repo https://github.com/nestjs/nest/security/advisories/GHSA-m8vh-jmq9-5rjg
- 2026-11-09T22:57:50+00:00 ghsa https://github.com/advisories/GHSA-m8vh-jmq9-5rjg
- 2026-11-09T23:10:12+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-102281

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/nestjs/nest/security/advisories/GHSA-m8vh-jmq9-5rjg
- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/nestjs/nest/security-advisories/GHSA-m8vh-jmq9-5rjg
- [fix] Patch: github.com https://github.com/nestjs/nest/pull/17737
- [fix] Patch: github.com https://github.com/nestjs/nest/commit/aa97b5144d8dff1ce700aac521eb86449a679d6f
- [fix] Patch: github.com https://github.com/nestjs/nest/commit/e9dcd4c7ac64361fbfe79461da85f5b3fc3e02da
- [fix] Release: github.com https://github.com/nestjs/nest/releases/tag/v11.2.4
- [fix] Release: github.com https://github.com/nestjs/nest/releases/tag/v12.0.2

## From the sources

| 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`) |
| Severity | High |
| CVSS v3.1 | `AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` (7.5) |
| CWE | CWE-674 (Uncontrolled Recursion), CWE-248 (Uncaught Exception) |

### 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.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
