GitHub Security Advisory: GHSA-chqc-8p9q-pq6q
Package: basic-ftp (NPM)
Severity: HIGH (CVSS 8.6)
CWE: CWE-93: Improper Neutralization of CRLF Sequences ('CRLF Injection')
Vulnerable versions: = 5.2.0
Patched in: 5.2.1

Summary: basic-ftp has FTP Command Injection via CRLF

Details:
## Summary

`basic-ftp` version `5.2.0` allows FTP command injection via CRLF sequences (`\r\n`) in file path parameters passed to high-level path APIs such as `cd()`, `remove()`, `rename()`, `uploadFrom()`, `downloadTo()`, `list()`, and `removeDir()`. The library's `protectWhitespace()` helper only handles leading spaces and returns other paths unchanged, while `FtpContext.send()` writes the resulting command string directly to the control socket with `\r\n` appended. This lets attacker-controlled path strings split one intended FTP command into multiple commands.

## Affected product

| Product | Affected versions | Fixed version |
| --- | --- | --- |
| basic-ftp (npm) | 5.2.0 (confirmed) | no fix available as of 2026-04-04 |

## Vulnerability details

- CWE: `CWE-93` - Improper Neutralization of CRLF Sequences ('CRLF Injection')
- CVSS 3.1: `8.6` (`High`)
- Vector: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L`
- Affected component: `dist/Client.js`, all path-handling methods via `protectWhitespace()` and `send()`

The vulnerability exists because of two interacting code patterns:

**1. Inadequate path sanitization in `protectWhitespace()` (line 677):**

```javascript
async protectWhitespace(path) {
    if (!path.startsWith(" ")) {
        return path;  // No sanitization of \r\n characters
    }
    const pwd = await this.pwd();
    const absolutePathPrefix = pwd.endsWith("/") ? pwd : pwd + "/";
    return absolutePathPrefix + path;
}
```

This function only handles leading whitespace. It does not strip or reject `\r` (0x0D) or `\n` (0x0A) characters anywhere in the path string.

**2. Direct socket write in `send()` (FtpContext.js line 177):**

```javascript
send(command) {
    this._socket.write(command + "\r\n", this.encoding);
}
```

The `send()` method appends `\r\n` to the command and writes directly to the TCP socket. If the command string already contains `\r\n` sequences (from unsanitized path input), the FTP server interprets them as command delimiters, causing the single intended command to be split into multiple commands.

**Affected methods** (all call `protectWhitespace()` → `send()`):
- `cd(path)` → `CWD ${path}`
- `remove(path)` → `DELE ${path}`
- `list(path)` → `LIST ${path}`
- `downloadTo(localPath, remotePath)` → `RETR ${remotePath}`
- `uploadFrom(localPath, remotePath)` → `STOR ${remotePath}`
- `rename(srcPath, destPath)` → `RNFR ${srcPath}` / `RNTO ${destPath}`
- `removeDir(path)` → `RMD ${path}`

## Technical impact

An attacker who controls file path parameters can inject arbitrary FTP protocol commands, enabling:

1. **Arbitrary file deletion**: Inject `DELE /critical-file` to delete files on the FTP server
2. **Directory manipulation**: Inject `MKD` or `RMD` commands to create/remove directories
3. **File exfiltration**: Inject `RETR` commands to trigger downloads of unintended files
4. **Server command execution**: On FTP servers supporting `SITE EXEC`, inject system commands
5. **Session hijacking**: Inject `USER`/`P