Like a hotel guest who checks in, floods the bathtub, then leaves without turning off the tap
CVE-2026-18549 affects @fastify/multipart versions 5.3.0 through 10.1.0. When an application uses request.saveRequestFiles() with a fileSize limit (the default configuration), an attacker can send an upload that exceeds the limit and then disconnect before sending the closing multipart boundary. This causes the request handler to hang indefinitely — no response is ever sent, the temporary file is never cleaned up, and the event loop slot is consumed. Repeated exploitation fills os.tmpdir() with orphaned temp files and exhausts Node.js worker capacity, producing a full denial of service. The fix is in version 10.1.1.
The vendor rates this HIGH / 7.5 with a standard unauthenticated-remote-DoS CVSS vector. That rating is *mostly fair* — the attack requires zero authentication, zero user interaction, and is dirt-cheap to execute (a single malformed multipart request plus a TCP reset). However, this is purely an availability impact with no path to code execution, data exfiltration, or lateral movement. The blast radius is the individual Fastify service process, which in most containerized deployments is recoverable via orchestrator restart. A trivial one-line workaround (throwFileSizeLimit: false) exists. These factors push the real-world severity slightly below the vendor label.
4 steps from start to impact.
Identify file-upload endpoint
request.saveRequestFiles(). Discovery can be done via normal HTTP probing or API documentation.- Target runs @fastify/multipart ≥5.3.0 and <10.1.1
- Target has at least one endpoint using saveRequestFiles()
- Not all Fastify apps accept file uploads
- Internal-only APIs behind an API gateway or WAF may not be reachable
Send oversized multipart payload
fileSize limit. The @fastify/busboy parser triggers the file-size-exceeded path, but the request handler awaits a promise that depends on the closing boundary.- fileSize limit is configured (default: 1MB)
- throwFileSizeLimit is not explicitly set to false
- If the app sets throwFileSizeLimit: false, this path is not reachable
- Rate-limiting or request-size enforcement at the reverse proxy layer can block oversized uploads
Abort connection before boundary
--boundary--. The busboy parser never emits the finish event, so saveRequestFiles() never resolves. The temp file is written to disk but never cleaned up. The request handler hangs, consuming an event-loop slot and a file descriptor.- Attacker controls when the TCP connection is closed
- Load balancers with request timeouts will eventually reclaim the connection, but the temp file remains on disk
- Container orchestrators may restart the pod, but accumulated temp files persist on the volume
os.tmpdir(); Node.js process health checks detecting hung workersRepeat to exhaust resources
os.tmpdir() and/or exhausts all available Node.js worker threads. Once disk is full, the target service (and potentially co-located services) fail. This is a classic asymmetric DoS — each attacker request costs kilobytes of bandwidth but consumes megabytes of disk.- No rate limiting on the upload endpoint
- Sufficient request volume to fill disk or exhaust workers before timeouts reclaim resources
- CDN/WAF rate limiting can throttle the attack
- Dedicated tmpdir volumes with quota limits contain the blast radius
- Kubernetes liveness probes restart hung pods, slowing disk accumulation
The supporting signals.
| In-the-Wild Exploitation | No known active exploitation as of 2026-08-15. Not listed on CISA KEV. Disclosed only one day ago (Aug 14, 2026). |
|---|---|
| Proof of Concept | No public PoC repository identified, but exploitation is trivially reproducible — a curl command sending a multipart body and then killing the connection suffices. No specialized tooling needed. |
| EPSS Score | Not yet scored by FIRST EPSS (CVE too new, published Aug 14 2026). Expect low-to-moderate EPSS given DoS-only impact. |
| KEV Status | Not listed. DoS-only vulnerabilities rarely make KEV. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — Network-accessible, no auth, no interaction, availability-only impact. Standard unauthenticated DoS vector. |
| Affected Versions | @fastify/multipart ≥ 5.3.0, < 10.1.1 (npm). The legacy fastify-multipart package (deprecated) is also affected if still in use. |
| Fixed Version | 10.1.1 (npm). No distro backports expected — this is a Node.js npm package. |
| Exposure / Install Base | ~290,000 weekly npm downloads; 429 dependent packages. Widely used in Fastify-based Node.js services. Not externally scannable — requires knowledge of specific endpoints. |
| Disclosure Date | 2026-08-14 via GitHub Security Advisory GHSA-vmph-573x-85f6. |
| Reporter | iaohkut-from-NightWolf-Team; fix by UlisesGascon, reviewed by mcollina. |
noisgate verdict.
Slight downgrade from vendor 7.5 to 6.5 driven by the single decisive factor: DoS-only impact with a trivial one-line configuration workaround (throwFileSizeLimit: false) that fully neutralizes the attack path without requiring a code deploy. The blast radius is limited to the individual Fastify service process — no path to code execution, data breach, or lateral movement exists.
Why this verdict
- Unauthenticated remote attack with zero complexity — the CVSS base score of 7.5 is technically accurate; any internet-facing Fastify upload endpoint is reachable without credentials.
- DoS-only, no escalation path — impact is purely availability. No memory corruption, no code execution, no data access. This caps the real-world severity below what an RCE at the same CVSS score would warrant.
- Trivial config workaround available — setting
throwFileSizeLimit: falsecompletely eliminates the vulnerable code path. This is a one-line change deployable via config management in minutes, dramatically reducing the urgency window. - Role multiplier: low —
@fastify/multipartruns inside Node.js application servers. In the typical role (API microservice behind a load balancer), a DoS kills one service instance that Kubernetes or a process manager restarts. In a high-value role scenario (e.g., a Fastify-based API gateway or file-ingestion service), the blast radius is still service-level, not fleet-level or identity-level. The affected component is not a hypervisor, IdP, domain controller, backup server, or security agent — it is an application-layer library. No high-value-role floor applies. - Disk exhaustion can cascade — the one factor preventing further downgrade: orphaned temp files accumulate on the host filesystem. If
os.tmpdir()shares a partition with other services or the OS root, disk exhaustion can impact co-located workloads, amplifying the blast radius beyond just the Fastify process.
Why not higher?
This cannot be CRITICAL because the impact is strictly availability — there is no code execution, no privilege escalation, no data exfiltration, and no lateral movement path. The affected component is an application-level npm library, not infrastructure software occupying a high-value role. A one-line config workaround fully mitigates the issue.
Why not lower?
This cannot be MEDIUM because the attack is unauthenticated, requires no user interaction, has trivially low complexity, and the disk exhaustion vector can cascade to co-located services. The ~290K weekly downloads indicate wide deployment, and the default configuration (fileSize limit enabled, throwFileSizeLimit not explicitly disabled) means most installations are vulnerable out of the box.
What to do — in priority order.
- Set throwFileSizeLimit: false in multipart plugin options — This is the vendor-recommended workaround. It bypasses the vulnerable code path entirely by not throwing on file size limit, preventing the hang. Deploy this config change within the noisgate mitigation SLA of 30 days for HIGH severity, though given the simplicity, aim for same-week.
- Set request timeouts at the reverse proxy layer — Configure nginx/HAProxy/ALB idle timeouts (e.g., 60s) to kill hung connections. This limits worker exhaustion but does NOT prevent temp file accumulation. Deploy as a defense-in-depth layer.
- Mount os.tmpdir() on a dedicated volume with quota — Isolate temp file storage so that exhaustion cannot cascade to the root filesystem or other services. Use
tmpfswith size limits in containers, or a dedicated EBS/PV with capacity alerts. - Rate-limit multipart POST endpoints — Apply per-IP rate limiting (e.g., 10 req/min) on upload endpoints via WAF or API gateway. This slows disk exhaustion significantly.
- Upgrade to @fastify/multipart 10.1.1 — The definitive fix. Plan this upgrade within the noisgate remediation SLA of 180 days for HIGH severity, but prioritize it given the low upgrade friction (minor version bump).
- Generic body-size WAF rules — the attack works with payloads that are only slightly above the fileSize limit (e.g., 1.1 MB against a 1 MB limit). Standard WAF max-body rules set to multi-MB thresholds will not catch this.
- Node.js cluster mode alone — while cluster mode provides multiple workers, each hung request still consumes a worker slot and writes a temp file. The attack simply requires more requests to exhaust all workers.
- Request body validation middleware — the hang occurs inside
saveRequestFiles()before any application-level validation runs. Middleware that validates request content after parsing cannot prevent the issue.
Crowdsourced verification payload.
Run this on any host or CI runner that has npm or node available. It checks the installed version of @fastify/multipart in the current project directory. No special privileges needed. Example: bash check_cve_2026_18549.sh /path/to/your/node/project
#!/usr/bin/env bash
# check_cve_2026_18549.sh — Detect CVE-2026-18549 in @fastify/multipart
# Usage: bash check_cve_2026_18549.sh [project_dir]
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
PROJECT_DIR="${1:-.}"
PKG_NAME="@fastify/multipart"
FIXED_VERSION="10.1.1"
MIN_AFFECTED="5.3.0"
if [ ! -d "$PROJECT_DIR/node_modules" ]; then
echo "UNKNOWN — node_modules not found in $PROJECT_DIR. Run npm install first or specify the correct project directory."
exit 2
fi
PKG_JSON="$PROJECT_DIR/node_modules/@fastify/multipart/package.json"
if [ ! -f "$PKG_JSON" ]; then
echo "UNKNOWN — $PKG_NAME is not installed in this project."
exit 2
fi
INSTALLED=$(node -e "console.log(require('$PKG_JSON').version)" 2>/dev/null)
if [ -z "$INSTALLED" ]; then
echo "UNKNOWN — could not read version from $PKG_JSON."
exit 2
fi
# Compare versions using node's semver-compatible comparison
RESULT=$(node -e "
const v = '$INSTALLED'.split('.').map(Number);
const fix = '$FIXED_VERSION'.split('.').map(Number);
const min = '$MIN_AFFECTED'.split('.').map(Number);
function cmp(a, b) { for (let i = 0; i < 3; i++) { if (a[i] !== b[i]) return a[i] - b[i]; } return 0; }
if (cmp(v, min) < 0) { console.log('NOT_AFFECTED'); }
else if (cmp(v, fix) >= 0) { console.log('PATCHED'); }
else { console.log('VULNERABLE'); }
")
if [ "$RESULT" = "PATCHED" ]; then
echo "PATCHED — @fastify/multipart $INSTALLED >= $FIXED_VERSION. CVE-2026-18549 is resolved."
exit 0
elif [ "$RESULT" = "NOT_AFFECTED" ]; then
echo "PATCHED — @fastify/multipart $INSTALLED is below the affected range ($MIN_AFFECTED). Not vulnerable."
exit 0
elif [ "$RESULT" = "VULNERABLE" ]; then
echo "VULNERABLE — @fastify/multipart $INSTALLED is in the affected range ($MIN_AFFECTED to <$FIXED_VERSION). Update to $FIXED_VERSION or set throwFileSizeLimit: false."
exit 1
else
echo "UNKNOWN — unexpected comparison result."
exit 2
fiIf you remember one thing.
npm ls @fastify/multipart across your Node.js services to identify affected deployments. For any service running versions 5.3.0 through 10.1.0, immediately apply the config workaround (throwFileSizeLimit: false) — this is a zero-risk, one-line change that fully neutralizes the attack. Per the noisgate mitigation SLA for HIGH severity, have this workaround deployed within 30 days, though given its simplicity, same-week is realistic and recommended. Then schedule the actual upgrade to @fastify/[email protected] under the noisgate remediation SLA of 180 days. Also check for the sibling CVE-2026-19474 (temp file leak on aborted upload), which is fixed in the same 10.1.1 release. If any of your Fastify upload services are internet-facing without rate limiting, prioritize those first — the attack is trivial to execute and requires no tooling beyond curl.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.