With over 18 million downloads, basic-ftp is a cornerstone utility for Node.js developers, offering a robust, Promise-based API for handling FTP, FTPS over TLS, and bulk directory operations. However, a newly disclosed vulnerability requires immediate attention from any development team utilizing this library to interact with external or untrusted servers.
Tracked as CVE-2026-27699, this Path Traversal vulnerability (CWE-22) carries a critical CVSS score of 9.1. It allows a malicious FTP server to escape the intended download directory on the client’s machine, potentially overwriting critical system files.
The vulnerability specifically resides within the downloadToDir() method.
Typically, when an FTP client downloads a directory, it requests a list of files from the server and saves them to a designated local folder. However, in this scenario, the threat model is flipped: the server is the malicious actor attacking the client.
By supplying a directory listing where filenames contain directory traversal sequences (such as ../../../etc/passwd), a rogue FTP server can trick the basic-ftp client into writing files far outside the boundaries of the safe, intended download directory.
The root cause of this vulnerability is a failure to properly sanitize untrusted input from the FTP server before passing it to the local file system. Here is the exact chain of events that makes the exploit possible:
-
The Malicious Payload (Source): The rogue FTP server responds to a
LISTcommand with a crafted file entry, such as:"-rw-r--r-- 1 user group 1024 Jan 20 12:00 ../../../etc/passwd". -
Flawed Validation: The library’s parser (
parseListUnix.ts) extracts the filename (../../../etc/passwd). The validation logic checks if the filename is exactly.or..to filter out current and parent directory pointers. Because the malicious string is not an exact match for those two characters, it passes the check. -
The Dangerous Merge (Sink): In
Client.ts, the application uses thepath.join()function to combine the safe local directory path with the malicious filename:join("/safe/download", "../../../etc/passwd"). -
Arbitrary Execution:
path.join()resolves the traversal sequences, resulting in the final path:/etc/passwd. The library then opens the file stream and writes the attacker’s data directly to that critical system location.
Because path.join() does not natively prevent traversal and fs.open() blindly resolves the resulting path, the impact on the client machine is severe.
If the Node.js application is running with sufficient privileges, a malicious FTP server can:
- Write arbitrary files to any location on the client’s filesystem.
- Overwrite critical system files, configuration files, or authorized SSH keys.
- Potentially achieve Remote Code Execution (RCE) by overwriting executable scripts, cron jobs, or application binaries.
The vulnerability has been confirmed in v5.1.0 and is likely present in all prior versions, as this code pattern has existed since the method’s initial implementation.
Maintainers have released version 5.2.0, which patches the vulnerability by utilizing path.basename() to strip out any directory paths provided by the server, ensuring only the raw filename is used. Development teams should upgrade their dependencies immediately.
If you cannot patch immediately, you must avoid using the downloadToDir() method when connecting to untrusted or externally controlled FTP servers. If downloading files individually, ensure your application manually sanitizes the file.name property before passing it to any file system operations.
Support Our Threat Intelligence
If you find our CVE report and cybersecurity news helpful, consider supporting our work.