CVE-2026-44240: Basic ftp Denial of Service Vulnerability

HIGH
Advisory Identifier: GHSA-rpmf-866q-6p89
CVSS 7.5
CWE-400 CWE-770
Published
Advisory Summary

CVE-2026-44240 is a HIGH (CVSS 7.5) denial of service vulnerability (CWE-400: Uncontrolled Resource Consumption) affecting Basic ftp libraries in the npm ecosystem. The issue involves basic-ftp allows a malicious ftp server to cause client-side denial of service via unbounded multiline control response buffering. Remediation is available by upgrading affected packages to version 5.3.1.

CVE-2026-44240 at a Glance

CVE Identifier CVE-2026-44240
GHSA Identifier GHSA-rpmf-866q-6p89
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-400: Uncontrolled Resource Consumption
Affected Product Basic ftp
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-44240

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

basic-ftp fixed: 5.3.1
npm install basic-ftp@5.3.1
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 basic-ftp

How to Check if You Are Affected

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

npm ls basic-ftp

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

Note: The npm ls basic-ftp 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-400: Uncontrolled Resource Consumption, where the product does not properly control the allocation and maintenance of a limited resource. In Basic ftp, 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

## Summary `basic-ftp` is vulnerable to client-side denial of service when parsing FTP control-channel multiline responses. A malicious or compromised FTP server can send an unterminated multiline response during the initial FTP banner phase, before authentication. The client keeps appending attacker-controlled data into `FtpContext._partialResponse` and repeatedly reparses the accumulated buffer without enforcing a maximum control response size. As a result, an application using `basic-ftp` can remain stuck in `connect()` while memory and CPU usage grow under attacker-controlled input. This can lead to process-level denial of service, container OOM kills, worker restarts, queue backlog, or service degradation in applications that automatically connect to FTP endpoints. --- ## Details ### Root cause The root cause is that incomplete FTP multiline control responses are buffered without an upper bound. `FtpContext` stores incomplete control-channel data in `_partialResponse`: https://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/FtpContext.ts#L63-L64 Incoming control-channel data is handled in `_onControlSocketData`. The implementation concatenates the previous incomplete response with the new chunk, parses the entire accumulated string, and stores `parsed.rest` back into `_partialResponse`: https://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/FtpContext.ts#L328-L340 The relevant flow is: completeResponse = this._partialResponse + chunk parsed = parseControlResponse(completeResponse) this._partialResponse = parsed.rest There is no maximum size check before concatenating, before parsing, or before storing `parsed.rest`. The parser accepts incomplete multiline responses and returns the entire unterminated multiline group as `rest`: https://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/parseControlResponse.ts#L15-L43 If a server starts a multiline FTP response: 220-malicious banner starts but never sends the terminating line: 220 ready then `parseControlResponse()` treats the accumulated multiline data as incomplete and returns it as `rest`. Because `_onControlSocketData()` feeds `_partialResponse + chunk` back into the parser on every new data event, the client repeatedly reparses a growing attacker-controlled buffer. This creates both memory growth and increasing parsing work. ### Why this is security-relevant The vulnerable component is a client library. The attacker does not need to authenticate to the victim system and does not need valid FTP credentials. The attack occurs automatically when an application using `basic-ftp` connects to a malicious or compromised FTP server. The malicious response is sent as the FTP server banner before login. No additional user interaction is required after the application initiates a normal FTP connection. This is realistic for applications that use FTP for: - scheduled imports or exports - customer-provided FTP endpoints - backup or synchronization jobs - CI/CD artifact mirroring - document ingestion pipelines - legacy business integrations In those environments, one malicious or compromised FTP endpoint can cause the Node.js process using `basic-ftp` to consume excessive memory and CPU or remain stuck in a pending connection state. --- ## Proof of Concept The PoC uses a local malicious FTP server that accepts a victim connection and sends an unterminated multiline FTP banner. The banner starts with `220-`, but the server never sends the required terminating `220 ` line. ### Reproduction steps From the root of the `basic-ftp` project: ```bash npm ci npm run buildOnly ``` [poc_control_parser_direct.js](https://github.com/user-attachments/files/27051425/poc_control_parser_direct.js) ```bash CHUNKS=1000 node poc_control_parser_direct.js | tee poc-results/parser_direct_1000.log ``` [parser_direct_1000.log](https://github.com/user-attachments/files/27051430/parser_direct_1000.log) Run the end-to-end malicious FTP server PoC: [poc_control_multiline_dos.js](https://github.com/user-attachments/files/27051385/poc_control_multiline_dos.js) ```bash CHUNK_SIZE=8192 CHUNKS=1000 DELAY_MS=1 node poc_control_multiline_dos.js | tee poc-results/control_multiline_dos_1000.log ``` [control_multiline_dos_1000.log](https://github.com/user-attachments/files/27051397/control_multiline_dos_1000.log) ### Observed result: parser-only PoC ```text [basic-ftp parseControlResponse incomplete multiline DoS] Input fed: 7.81 MiB Retained rest: 7.81 MiB Initial rss/heap: 54.77 MiB 3.69 MiB Final rss/heap: 141.64 MiB 80.77 MiB ``` This shows that `parseControlResponse()` retained the full unterminated multiline response as `rest`. The retained buffer grew to `7.81 MiB`. Heap usage increased from `3.69 MiB` to `80.77 MiB`, and RSS increased from `54.77 MiB` to `141.64 MiB`. ### Observed result: end-to-end malicious FTP server PoC ```text [server] listening on 127.0.0.1:34429 [server] victim connected [progress] chunks=850 sent=6.6 MiB partialResponse=6.6 MiB heapUsed=227.5 MiB rss=292.4 MiB [progress] chunks=900 sent=7.0 MiB partialResponse=7.0 MiB heapUsed=213.1 MiB rss=278.0 MiB [final-before-close] chunks=1000 sent=7.8 MiB partialResponse=7.8 MiB heapUsed=82.1 MiB rss=146.8 MiB [result] client connect() is still pending because the multiline response never terminated ``` Only `7.8 MiB` of malicious control-channel data was sent. The client retained `7.8 MiB` in `_partialResponse`, showed large memory spikes, and remained pending inside `connect()` because the multiline response was never terminated. --- ## Expected behavior The client should enforce a maximum size for incomplete FTP control responses. If the accumulated multiline response exceeds a safe limit, the client should close the connection and reject the active task with an error. The client should not allow a remote FTP server to make `_partialResponse` grow without bound. --- ## Actual behavior A malicious FTP server can keep the client in a pending connection state by sending an unterminated multiline control response. `basic-ftp` continues buffering and reparsing the accumulated data without a maximum response size. --- ## Impact A malicious or compromised FTP server can cause denial of service in applications using `basic-ftp`. Possible real-world impact includes: - Node.js process memory exhaustion - container OOM kill - worker crash or restart loop - event loop CPU pressure due to repeated reparsing - stuck FTP jobs - queue backlog in scheduled import/export systems - degraded availability of services relying on automated FTP ingestion --- ## Threat model The attacker controls, compromises, or can impersonate an FTP server that a victim application connects to. Examples: 1. A SaaS application allows customers to configure external FTP endpoints for automated imports. 2. A backend job periodically pulls files from partner FTP servers. 3. A document ingestion pipeline connects to FTP endpoints supplied by external users. 4. A legacy integration uses FTP for scheduled synchronization. 5. A build or deployment pipeline mirrors artifacts from an FTP server. In each case, the victim application initiates a normal FTP connection. The malicious server sends an unterminated multiline banner before authentication. The vulnerable client then buffers and reparses the response indefinitely. No FTP credentials are required for exploitation because the attack happens before login. --- ## Suggested fix Introduce a maximum control response buffer size, especially for incomplete multiline responses. Recommended changes: - Add a `maxControlResponseBytes` or `maxControlResponseLength` limit. - Enforce the limit before or immediately after appending new control-channel data. - Close the connection and reject the active task when the limit is exceeded. - Add regression tests for unterminated multiline responses. Example defensive logic: ```text if (completeResponse.length > maxControlResponseLength) { closeWithError(new Error("FTP control response exceeded maximum allowed size")) } ``` A regression test should verify that a response beginning with `220-` and never terminating with `220 ` is rejected after the configured size limit instead of being retained indefinitely. --- ## Suggested regression test scenario A test server should: 1. Accept a client connection. 2. Send an FTP multiline response opener such as `220-malicious banner\r\n`. 3. Continue sending additional lines without ever sending the terminating `220 ` line. 4. Verify that the client rejects the connection once the configured response-size limit is exceeded. 5. Verify that `_partialResponse` does not grow without bound. ## Credit request If you publish an advisory or assign a CVE, please credit me as: Ali Firas (thesmartshadow) - https://www.smartshadow.dev

CVE-2026-44240 Affected Basic ftp Versions

1 component(s)
Fixed Versions:
5.3.1
Product / Package Ecosystem Affected Versions Fixed Version
basic-ftp
npm
< 5.3.1
5.3.1

References

Frequently Asked Questions

What is CVE-2026-44240?
CVE-2026-44240 is a security vulnerability in Basic ftp involving basic-ftp allows a malicious FTP server to cause client-side denial of service via unbounded multiline control response buffering under CWE-400: Uncontrolled Resource Consumption.
Which Basic ftp versions are affected?
Affected versions include releases prior to 5.3.1 across affected packages: basic-ftp.
What version fixes CVE-2026-44240?
Upgrading to 5.3.1 (or the latest patched release for your respective branch) resolves the vulnerability.
Is basic-ftp affected?
Yes, basic-ftp is affected in releases prior to 5.3.1. Upgrade your dependency to 5.3.1 or later.
What is the CVSS score of CVE-2026-44240?
CVE-2026-44240 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-44240?
CVE-2026-44240 is classified under CWE-400: Uncontrolled Resource Consumption (The product does not properly control the allocation and maintenance of a limited resource.).
How can I check npm dependencies for CVE-2026-44240?
Run the dependency tree command: 'npm ls basic-ftp'. 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-rpmf-866q-6p89",
  "modified" : "2026-05-13T16:29:59Z",
  "published" : "2026-05-06T19:37:33Z",
  "aliases" : [ "CVE-2026-44240" ],
  "summary" : "basic-ftp allows a malicious FTP server to cause client-side denial of service via unbounded multiline control response buffering",
  "details" : "## Summary\n\n`basic-ftp` is vulnerable to client-side denial of service when parsing FTP control-channel multiline responses.\n\nA malicious or compromised FTP server can send an unterminated multiline response during the initial FTP banner phase, before authentication. The client keeps appending attacker-controlled data into `FtpContext._partialResponse` and repeatedly reparses the accumulated buffer without enforcing a maximum control response size.\n\nAs a result, an application using `basic-ftp` can remain stuck in `connect()` while memory and CPU usage grow under attacker-controlled input. This can lead to process-level denial of service, container OOM kills, worker restarts, queue backlog, or service degradation in applications that automatically connect to FTP endpoints.\n\n---\n\n## Details\n\n### Root cause\n\nThe root cause is that incomplete FTP multiline control responses are buffered without an upper bound.\n\n`FtpContext` stores incomplete control-channel data in `_partialResponse`:\n\n\nhttps://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/FtpContext.ts#L63-L64\n\n\nIncoming control-channel data is handled in `_onControlSocketData`. The implementation concatenates the previous incomplete response with the new chunk, parses the entire accumulated string, and stores `parsed.rest` back into `_partialResponse`:\n\n\nhttps://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/FtpContext.ts#L328-L340\n\n\nThe relevant flow is:\n\n\ncompleteResponse = this._partialResponse + chunk\nparsed = parseControlResponse(completeResponse)\nthis._partialResponse = parsed.rest\n\n\nThere is no maximum size check before concatenating, before parsing, or before storing `parsed.rest`.\n\nThe parser accepts incomplete multiline responses and returns the entire unterminated multiline group as `rest`:\n\n\nhttps://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/parseControlResponse.ts#L15-L43\n\n\nIf a server starts a multiline FTP response:\n\n\n220-malicious banner starts\n\n\nbut never sends the terminating line:\n\n\n220 ready\n\n\nthen `parseControlResponse()` treats the accumulated multiline data as incomplete and returns it as `rest`.\n\nBecause `_onControlSocketData()` feeds `_partialResponse + chunk` back into the parser on every new data event, the client repeatedly reparses a growing attacker-controlled buffer. This creates both memory growth and increasing parsing work.\n\n### Why this is security-relevant\n\nThe vulnerable component is a client library. The attacker does not need to authenticate to the victim system and does not need valid FTP credentials.\n\nThe attack occurs automatically when an application using `basic-ftp` connects to a malicious or compromised FTP server. The malicious response is sent as the FTP server banner before login. No additional user interaction is required after the application initiates a normal FTP connection.\n\nThis is realistic for applications that use FTP for:\n\n- scheduled imports or exports\n- customer-provided FTP endpoints\n- backup or synchronization jobs\n- CI/CD artifact mirroring\n- document ingestion pipelines\n- legacy business integrations\n\nIn those environments, one malicious or compromised FTP endpoint can cause the Node.js process using `basic-ftp` to consume excessive memory and CPU or remain stuck in a pending connection state.\n\n---\n\n## Proof of Concept\n\nThe PoC uses a local malicious FTP server that accepts a victim connection and sends an unterminated multiline FTP banner. The banner starts with `220-`, but the server never sends the required terminating `220 ` line.\n\n### Reproduction steps\n\nFrom the root of the `basic-ftp` project:\n\n```bash\nnpm ci\nnpm run buildOnly\n```\n\n[poc_control_parser_direct.js](https://github.com/user-attachments/files/27051425/poc_control_parser_direct.js)\n\n```bash\nCHUNKS=1000 node poc_control_parser_direct.js | tee poc-results/parser_direct_1000.log\n```\n\n[parser_direct_1000.log](https://github.com/user-attachments/files/27051430/parser_direct_1000.log)\n\nRun the end-to-end malicious FTP server PoC:\n\n[poc_control_multiline_dos.js](https://github.com/user-attachments/files/27051385/poc_control_multiline_dos.js)\n\n```bash\nCHUNK_SIZE=8192 CHUNKS=1000 DELAY_MS=1 node poc_control_multiline_dos.js | tee poc-results/control_multiline_dos_1000.log\n```\n\n[control_multiline_dos_1000.log](https://github.com/user-attachments/files/27051397/control_multiline_dos_1000.log)\n\n### Observed result: parser-only PoC\n\n```text\n[basic-ftp parseControlResponse incomplete multiline DoS]\nInput fed: 7.81 MiB\nRetained rest: 7.81 MiB\nInitial rss/heap: 54.77 MiB 3.69 MiB\nFinal   rss/heap: 141.64 MiB 80.77 MiB\n```\n\nThis shows that `parseControlResponse()` retained the full unterminated multiline response as `rest`.\n\nThe retained buffer grew to `7.81 MiB`. Heap usage increased from `3.69 MiB` to `80.77 MiB`, and RSS increased from `54.77 MiB` to `141.64 MiB`.\n\n### Observed result: end-to-end malicious FTP server PoC\n\n```text\n[server] listening on 127.0.0.1:34429\n[server] victim connected\n[progress] chunks=850 sent=6.6 MiB partialResponse=6.6 MiB heapUsed=227.5 MiB rss=292.4 MiB\n[progress] chunks=900 sent=7.0 MiB partialResponse=7.0 MiB heapUsed=213.1 MiB rss=278.0 MiB\n[final-before-close] chunks=1000 sent=7.8 MiB partialResponse=7.8 MiB heapUsed=82.1 MiB rss=146.8 MiB\n[result] client connect() is still pending because the multiline response never terminated\n```\n\nOnly `7.8 MiB` of malicious control-channel data was sent. The client retained `7.8 MiB` in `_partialResponse`, showed large memory spikes, and remained pending inside `connect()` because the multiline response was never terminated.\n\n---\n\n## Expected behavior\n\nThe client should enforce a maximum size for incomplete FTP control responses. If the accumulated multiline response exceeds a safe limit, the client should close the connection and reject the active task with an error.\n\nThe client should not allow a remote FTP server to make `_partialResponse` grow without bound.\n\n---\n\n## Actual behavior\n\nA malicious FTP server can keep the client in a pending connection state by sending an unterminated multiline control response. `basic-ftp` continues buffering and reparsing the accumulated data without a maximum response size.\n\n---\n\n## Impact\n\nA malicious or compromised FTP server can cause denial of service in applications using `basic-ftp`.\n\nPossible real-world impact includes:\n\n- Node.js process memory exhaustion\n- container OOM kill\n- worker crash or restart loop\n- event loop CPU pressure due to repeated reparsing\n- stuck FTP jobs\n- queue backlog in scheduled import/export systems\n- degraded availability of services relying on automated FTP ingestion\n\n---\n\n## Threat model\n\nThe attacker controls, compromises, or can impersonate an FTP server that a victim application connects to.\n\nExamples:\n\n1. A SaaS application allows customers to configure external FTP endpoints for automated imports.\n2. A backend job periodically pulls files from partner FTP servers.\n3. A document ingestion pipeline connects to FTP endpoints supplied by external users.\n4. A legacy integration uses FTP for scheduled synchronization.\n5. A build or deployment pipeline mirrors artifacts from an FTP server.\n\nIn each case, the victim application initiates a normal FTP connection. The malicious server sends an unterminated multiline banner before authentication. The vulnerable client then buffers and reparses the response indefinitely.\n\nNo FTP credentials are required for exploitation because the attack happens before login.\n\n---\n\n## Suggested fix\n\nIntroduce a maximum control response buffer size, especially for incomplete multiline responses.\n\nRecommended changes:\n\n- Add a `maxControlResponseBytes` or `maxControlResponseLength` limit.\n- Enforce the limit before or immediately after appending new control-channel data.\n- Close the connection and reject the active task when the limit is exceeded.\n- Add regression tests for unterminated multiline responses.\n\nExample defensive logic:\n\n```text\nif (completeResponse.length > maxControlResponseLength) {\n    closeWithError(new Error(\"FTP control response exceeded maximum allowed size\"))\n}\n```\n\nA regression test should verify that a response beginning with `220-` and never terminating with `220 ` is rejected after the configured size limit instead of being retained indefinitely.\n\n---\n\n## Suggested regression test scenario\n\nA test server should:\n\n1. Accept a client connection.\n2. Send an FTP multiline response opener such as `220-malicious banner\\r\\n`.\n3. Continue sending additional lines without ever sending the terminating `220 ` line.\n4. Verify that the client rejects the connection once the configured response-size limit is exceeded.\n5. Verify that `_partialResponse` does not grow without bound.\n\n## Credit request\nIf you publish an advisory or assign a CVE, please credit me as:\n\nAli Firas (thesmartshadow)  - https://www.smartshadow.dev",
  "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" : "basic-ftp"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "5.3.1"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 5.3.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/patrickjuchli/basic-ftp/security/advisories/GHSA-rpmf-866q-6p89"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-44240"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/patrickjuchli/basic-ftp"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-400", "CWE-770" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-06T19:37:33Z",
    "nvd_published_at" : "2026-05-12T21:16:16Z"
  }
}