Back to Blog
high SEVERITY8 min read

How Client-Side Denial of Service happens in Node.js FTP clients and how to fix it

CVE-2026-44240 is a client-side Denial of Service vulnerability in the `basic-ftp` Node.js package (versions prior to 5.3.1) caused by improper handling of unterminated multiline FTP server responses. An attacker controlling an FTP server—or capable of intercepting FTP traffic—could send a malformed response that causes the client to hang indefinitely. Upgrading `basic-ftp` to 5.3.1 and adding a package override in `package.json` closes the attack surface entirely.

O
By Orbis AppSec
Published August 23, 2026Reviewed August 23, 2026

Answer Summary

CVE-2026-44240 is a client-side Denial of Service (DoS) vulnerability in the `basic-ftp` Node.js FTP client library, classified under CWE-400 (Uncontrolled Resource Consumption). In versions before 5.3.1, the library fails to properly handle unterminated multiline FTP server responses, allowing a malicious or compromised FTP server to cause the client process to hang indefinitely. The fix is to upgrade `basic-ftp` to version 5.3.1 and add a `package.json` override to ensure no transitive dependency pulls in the vulnerable version.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixUpgrade basic-ftp from 5.3.0 to 5.3.1 and add a package.json override to pin the safe version
riskAn attacker-controlled FTP server can hang the client process indefinitely, causing application unavailability
languageJavaScript / Node.js
root causebasic-ftp <5.3.1 does not enforce a termination condition when parsing multiline FTP server responses
vulnerabilityClient-Side Denial of Service via unterminated multiline FTP responses

How Client-Side Denial of Service Happens in Node.js FTP Clients and How to Fix It


Vulnerability at a Glance

Field Detail
CVE CVE-2026-44240
Severity HIGH
Package basic-ftp < 5.3.1
CWE CWE-400: Uncontrolled Resource Consumption
Fix Upgrade to basic-ftp 5.3.1 + add package.json override

Direct Answer: CVE-2026-44240 is a client-side Denial of Service vulnerability in the basic-ftp Node.js FTP client library (CWE-400). Versions before 5.3.1 fail to handle unterminated multiline FTP server responses, allowing a malicious server to hang the client indefinitely. Fix it by upgrading to 5.3.1 and pinning the version with a package.json override.


Introduction

The openclaw-project-dashboard project uses basic-ftp to interact with FTP servers as part of its file management workflow. Trivy's software composition analysis flagged a HIGH-severity vulnerability in package-lock.json: the project was running basic-ftp version 5.3.0, which is vulnerable to a client-side Denial of Service attack via unterminated multiline FTP server responses (CVE-2026-44240).

This vulnerability is particularly interesting because the attack surface is on the client side — meaning your Node.js application is the victim, not the FTP server. If your application connects to any FTP server you don't fully control, or if an attacker can perform a man-in-the-middle attack on your FTP connection, they can exploit this flaw to hang your application process indefinitely.


The Vulnerability Explained

What Are Multiline FTP Responses?

The FTP protocol (RFC 959) allows servers to send multiline responses. A standard single-line FTP response looks like this:

220 Welcome to FTP server

A multiline response uses a specific format: the first line uses a hyphen (-) after the status code, and the final line uses a space after the same status code to signal termination:

220-Welcome to the FTP server
220-Please read the terms of service
220 Ready.

The critical detail: the client must keep reading lines until it sees the terminating line (status code + space). If the terminating line never arrives, the client is supposed to detect this and handle it gracefully.

The Flaw in basic-ftp 5.3.0

In basic-ftp versions prior to 5.3.1, the response parser does not properly enforce a termination condition when it encounters a multiline response that never sends its closing line. Instead of timing out or raising an error, the client continues waiting — consuming the event loop and blocking any further FTP operations.

The vulnerable behavior can be triggered with a crafted server response like:

220-This is a multiline response that never ends
220-Keep reading...
220-Still going...
[connection hangs here  no terminating "220 " line ever arrives]

Because basic-ftp 5.3.0 does not guard against this, the client process stalls. In a Node.js application, this means the event loop is blocked waiting for data that will never come, effectively causing a Denial of Service for any code path that depends on FTP operations completing.

Real-World Attack Scenario for openclaw-project-dashboard

Consider this concrete scenario for the openclaw-project-dashboard application:

  1. The dashboard connects to an FTP server to retrieve project files or upload build artifacts.
  2. An attacker who controls the FTP server (or who can perform a DNS hijack or MITM attack on the FTP connection) sends a malformed greeting or response that begins a multiline sequence but never terminates it.
  3. The basic-ftp 5.3.0 client in the dashboard hangs, waiting for the response to complete.
  4. The dashboard's file operations stall. Depending on how the application handles this, the entire Node.js process may become unresponsive, taking down the dashboard for all users.

This is especially dangerous in CI/CD pipelines or automated deployment workflows where FTP connections are made programmatically without human oversight — a hang in these contexts can silently block deployments.

Why This Is Classified HIGH Severity

  • No authentication required on the attacker's part — the malicious response is sent before any credentials are exchanged (e.g., in the FTP server greeting).
  • Full process hang — not just a slow operation, but an indefinite block.
  • Broad applicability — any code path in openclaw-project-dashboard that initiates an FTP connection is affected.

The Fix

The fix required changes to two files: package-lock.json and package.json.

1. Upgrading basic-ftp in package-lock.json

The core change was upgrading basic-ftp from 5.3.0 to 5.3.1:

Before (vulnerable):

"node_modules/basic-ftp": {
  "version": "5.3.0",
  "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.0.tgz",
  "integrity": "sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w=="
}

After (patched):

"node_modules/basic-ftp": {
  "version": "5.3.1",
  "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz",
  "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw=="
}

The new integrity hash (sha512-bopVNp6ugyA150DDu...) cryptographically verifies that the installed package is exactly the patched 5.3.1 release — not a tampered or older version.

2. Adding a package.json Override

This is the critical second step that many developers miss. Simply updating package-lock.json is not sufficient if basic-ftp is also pulled in as a transitive dependency by another package in the tree. To guarantee that no nested dependency can re-introduce basic-ftp 5.3.0, an overrides entry was added to package.json:

Before:

{
  "devDependencies": {
    "@playwright/test": "^1.59.1"
  }
}

After:

{
  "devDependencies": {
    "@playwright/test": "^1.59.1"
  },
  "overrides": {
    "basic-ftp": "5.3.1"
  }
}

The overrides field (supported in npm 8.3+) forces npm to resolve basic-ftp to exactly 5.3.1 throughout the entire dependency tree — direct and transitive. This is a defense-in-depth measure that prevents the vulnerability from sneaking back in via a nested dependency update.

What Changed Inside basic-ftp 5.3.1?

The 5.3.1 patch adds proper termination detection to the multiline FTP response parser. The fix ensures that if a server response begins a multiline sequence (line ending with - after the status code) but never delivers the closing line, the parser will either time out or raise a parse error — rather than waiting indefinitely. Valid, well-formed FTP responses are completely unaffected.


Prevention & Best Practices

1. Use Software Composition Analysis (SCA) in CI/CD

Tools like Trivy, Snyk, and Dependabot scan your package-lock.json for known-vulnerable dependency versions. This vulnerability was caught by Trivy's rule CVE-2026-44240. Integrate SCA scanning into every pull request pipeline.

2. Always Add npm Overrides for Security Patches

When a transitive dependency has a known CVE, don't rely solely on updating package-lock.json. Always add an overrides entry in package.json:

"overrides": {
  "vulnerable-package": "safe-version"
}

For Yarn users, use resolutions. For pnpm, use pnpm.overrides.

3. Implement FTP Connection Timeouts at the Application Layer

Even with the patched library, it's good practice to set explicit timeouts on FTP operations in your application code:

const client = new ftp.Client();
client.ftp.timeout = 30000; // 30 second timeout

This provides an additional layer of protection against any future response-parsing issues.

4. Prefer SFTP or FTPS Over Plain FTP

Plain FTP transmits data (including credentials) in cleartext and is more susceptible to MITM attacks that could exploit vulnerabilities like this one. Where possible, use SFTP (SSH File Transfer Protocol) or FTPS (FTP over TLS).

5. Keep Dependencies Minimal and Audited

Run npm audit regularly and automate dependency updates with tools like Renovate or Dependabot. The smaller and more up-to-date your dependency tree, the smaller your attack surface.

Relevant Standards


Key Takeaways

  • Unterminated multiline FTP responses are a real attack vector: basic-ftp 5.3.0's response parser has no termination guard, meaning a malicious server can hang your Node.js process with a single malformed response line.
  • Updating package-lock.json alone is not enough: The overrides entry in package.json is essential to prevent transitive dependencies from re-introducing the vulnerable 5.3.0 version.
  • The attack requires no credentials: The malicious response can be delivered in the FTP server greeting, before any authentication occurs — making the attack trivially easy to execute.
  • SCA tools catch what code review misses: This vulnerability was not visible in application source code; it lived in package-lock.json and was only caught by Trivy's dependency scanning.
  • FTP clients in Node.js deserve the same security scrutiny as HTTP clients: DoS vulnerabilities in protocol parsers are just as dangerous as injection vulnerabilities in business logic.

How Orbis AppSec Detected This

  • Source: The tainted data enters via the FTP server's response stream — specifically, a multiline response that begins with a 220- (or similar status-hyphen) prefix but never delivers the terminating 220 (status-space) closing line.
  • Sink: The dangerous call site is basic-ftp's internal response parser, which reads lines from the FTP socket in a loop without a maximum-iteration or timeout guard in version 5.3.0.
  • Missing control: No termination bound or read timeout was enforced on the multiline response accumulation loop, allowing an infinite wait on attacker-controlled input.
  • CWE: CWE-400 — Uncontrolled Resource Consumption
  • Fix: basic-ftp was upgraded from 5.3.0 to 5.3.1 in package-lock.json, and an overrides entry was added to package.json to pin the safe version across the entire dependency tree.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2026-44240 is a reminder that Denial of Service vulnerabilities don't always come from your own code — they can hide in the protocol parsers of the libraries you depend on. In openclaw-project-dashboard, basic-ftp 5.3.0's failure to handle unterminated multiline FTP responses meant that any FTP connection to an untrusted or compromised server could hang the entire application.

The fix is straightforward but has two required parts: upgrading the package in package-lock.json and adding an overrides entry in package.json. Miss the second step, and the vulnerability can silently return through a transitive dependency update. With both changes in place, the application is protected against this specific attack vector, and the fix is future-proofed against dependency tree reshuffling.

Treat your package-lock.json as a security artifact, not just a reproducibility tool. Run SCA scans on every commit, and let automated tools like Orbis AppSec catch what manual code review cannot.


References

Frequently Asked Questions

What is a client-side Denial of Service in an FTP library?

It means a malicious or compromised FTP server can send a specially crafted response that causes the FTP client library to consume excessive resources or hang, making the application unavailable without crashing the server itself.

How do you prevent unterminated multiline response DoS in Node.js FTP clients?

Always use a patched version of your FTP client library (basic-ftp ≥5.3.1), add package overrides in package.json to prevent transitive dependencies from pulling in vulnerable versions, and validate or timeout FTP connections in your application layer.

What CWE is this Denial of Service vulnerability?

CWE-400: Uncontrolled Resource Consumption, where the library fails to bound the resources spent parsing an endless or unterminated server response.

Is upgrading the direct dependency enough to prevent this vulnerability?

Not always. If basic-ftp is also a transitive dependency (pulled in by another package), you must add a `overrides` entry in package.json to force all consumers to use the safe version.

Can static analysis detect this type of vulnerability?

Yes. Trivy and similar software composition analysis (SCA) tools flag known-vulnerable package versions in package-lock.json, which is exactly how this CVE was detected in the openclaw-project-dashboard project.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #18

Related Articles

high

How javascript.express.security.audit.express-check-csurf-middleware-usage.express-check-csurf-middleware-usage happens in Express.js and how to fix it

A publicly accessible Express.js API endpoint in `app/api/cameras.js` was missing CSRF protection, leaving state-changing requests (POST, PUT, DELETE, PATCH) vulnerable to cross-site request forgery attacks. The fix introduces Origin/Referer header validation middleware in `app/index.js` and removes a redundant Express instance from `cameras.js` that bypassed the application's middleware chain.

critical

How Command Injection via Unescaped Line Terminators Happens in Node.js and How to Fix It

A critical command injection vulnerability (CVE-2026-9277) was discovered in the shell-quote npm package version 1.8.3, where unescaped line terminators could allow attackers to execute arbitrary code. This fix upgrades shell-quote to version 1.9.0 using npm overrides to ensure all instances in the dependency tree are patched, eliminating the attack vector across the entire application.

critical

How Distributed Lock Takeover Happens in Node.js and How to Fix It

A critical vulnerability in `redis-lock/server.mjs` allowed any authenticated client to release another client's lock by guessing predictable holder identifiers like process IDs or hostnames. The fix implements cryptographically random `lockId` values that are minted on lock acquisition and validated on release, eliminating the exploit primitive entirely.

high

How Denial of Service via Infinite Loop happens in JavaScript (nanoid) and how to fix it

A high-severity denial of service vulnerability (CVE-2026-67213) was discovered in nanoid versions before 5.1.6 and 3.3.18, where the `customAlphabet` function could enter an infinite loop during random ID generation. The fix upgrades the transitive nanoid dependency from 3.3.16 to 3.3.18 using pnpm overrides, ensuring the vulnerable code path is eliminated from the entire dependency tree including PostCSS.

high

How Information Disclosure via Unstripped Credential Headers Happens in Electron Apps and How to Fix It

A high-severity vulnerability (CVE-2026-54673) in the builder-util-runtime package allowed sensitive credential headers to leak during HTTP redirects in Electron applications. The fix upgrades builder-util-runtime from version 9.5.1 to 9.7.0, which properly strips authentication headers before following redirects to prevent information disclosure.

high

How Information Disclosure and DoS via malformed Cache-Control directives happens in Node.js undici and how to fix it

A high-severity vulnerability (CVE-2026-13697) in the undici HTTP client library allowed attackers to trigger information disclosure and denial of service through malformed Cache-Control directives. The @jackwener/opencli project upgraded undici from version 7.24.6 to 7.29.0, eliminating the vulnerability in their dependency chain and protecting downstream consumers from exploitation.