Back to Blog
critical SEVERITY8 min read

How Path Traversal in basic-ftp Leads to File Overwrite Attacks and How to Fix It

CVE-2026-27699 is a critical path traversal vulnerability in basic-ftp versions before 5.3.1 that allows attackers to overwrite arbitrary files on the system by crafting malicious file paths. This vulnerability was fixed by upgrading basic-ftp and enforcing strict version constraints across dependent packages. Understanding this attack and its mitigation is essential for developers using FTP libraries in production environments.

O
By Orbis AppSec
Published September 6, 2026Reviewed September 6, 2026

Answer Summary

CVE-2026-27699 is a critical path traversal vulnerability (CWE-22) in the basic-ftp Node.js library that allows attackers to overwrite arbitrary files by injecting directory traversal sequences (like `../`) into file paths during FTP operations. The fix upgrades basic-ftp from 5.1.0 to 5.3.1, which implements proper path validation and sanitization to reject malicious path components. Additionally, dependency overrides ensure all transitive dependencies use the patched version.

Vulnerability at a Glance

cweCWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
fixUpgrade to basic-ftp 5.3.1 which implements strict path validation, and enforce version constraints across all transitive dependencies
riskAttackers can overwrite critical application files, configuration files, or system files, leading to code execution, data corruption, or denial of service
languageJavaScript/Node.js
root causebasic-ftp 5.1.0 failed to properly validate and sanitize file paths before performing file operations, allowing `../` sequences to escape intended directories
vulnerabilityPath Traversal / Directory Traversal (File Overwrite)

How Path Traversal in basic-ftp Leads to File Overwrite Attacks and How to Fix It

Introduction

In a Node.js application using the basic-ftp library, a critical vulnerability lurked in the dependency tree: CVE-2026-27699, a path traversal flaw that could allow attackers to overwrite arbitrary files on the system. The vulnerability existed in basic-ftp version 5.1.0, which was referenced in package-lock.json as a direct or transitive dependency. Unlike many vulnerabilities that require complex exploitation chains, this one was deceptively simple—an attacker could craft a malicious FTP filename containing directory traversal sequences like ../ and bypass the library's file path validation, potentially overwriting critical application files, configuration files, or even system binaries.

The fix was straightforward but critical: upgrade basic-ftp from 5.1.0 to 5.3.1 and enforce this version across all transitive dependencies using npm overrides. This blog post dissects the vulnerability, explains the attack mechanism, and demonstrates how the fix eliminates the risk.


The Vulnerability Explained

What Went Wrong in basic-ftp 5.1.0

Path traversal vulnerabilities in file operations occur when an application fails to properly validate file paths before performing operations like read, write, or delete. In the case of basic-ftp 5.1.0, the library accepted file paths from FTP commands without sufficiently sanitizing them.

Consider a typical FTP scenario: a user initiates an FTP connection and downloads a file named document.pdf. The basic-ftp library handles the file path and writes it to disk. But what if an attacker sends a specially crafted filename like:

../../../../etc/passwd

or

../../../config/database.yml

In version 5.1.0, the library did not properly validate these paths. Instead of rejecting the traversal sequences or resolving the canonical path to verify it remained within the intended directory, basic-ftp would process the path as-is, allowing the attacker to:

  1. Overwrite application configuration files (e.g., .env, config.json)
  2. Replace application code (e.g., index.js, middleware files)
  3. Corrupt database files or other critical data
  4. Inject malicious code that would be executed on the next application restart

Attack Scenario: Real-World Impact

Imagine a Node.js web application that uses basic-ftp to download files from a corporate FTP server:

// Vulnerable code pattern (basic-ftp 5.1.0)
const Client = require('basic-ftp').Client;

async function downloadFile(filename) {
  const client = new Client();
  await client.access(ftpConfig);
  await client.downloadTo(`./uploads/${filename}`, filename);
  await client.close();
}

// Attacker calls: downloadFile('../../../src/app.js')
// Result: The file is downloaded and saved to ./src/app.js, overwriting the main app file

An attacker on the FTP server (or intercepting the connection) could provide a filename like ../../../src/app.js. Because basic-ftp 5.1.0 didn't validate the path, it would:

  1. Accept the traversal sequence
  2. Resolve the path to ./src/app.js (outside the intended ./uploads/ directory)
  3. Overwrite the actual application file

On the next application restart, the malicious code would execute with full application privileges.

Why This Is Critical

The CVSS score for this vulnerability is CRITICAL because:

  • Easy to exploit: No special tools or deep technical knowledge required; just craft a filename
  • High impact: Can lead to remote code execution (RCE), data exfiltration, or complete system compromise
  • Wide reach: Any application using basic-ftp for file downloads is affected
  • Supply chain risk: The vulnerability exists in the dependency tree, affecting applications that don't directly use basic-ftp but depend on packages that do (like firebase-tools, get-uri, pac-proxy-agent, and proxy-agent)

The Fix

What Changed: Upgrade from 5.1.0 to 5.3.1

The fix involved two key changes reflected in the PR:

1. Primary Change: Upgrade basic-ftp in package-lock.json

"node_modules/basic-ftp": {
-  "version": "5.1.0",
-  "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz",
-  "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==",
+  "version": "5.3.1",
+  "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz",
+  "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==",
   "license": "MIT",
   "engines": {
     "node": ">=10.0.0"

This upgrade ensures that when dependencies are installed, version 5.3.1 (with path validation fixes) is used instead of the vulnerable 5.1.0.

2. Secondary Change: Add npm Overrides in package.json

"overrides": {
  "basic-ftp": {
    "basic-ftp": "5.3.1"
  },
  "firebase-tools": {
    "basic-ftp": "5.3.1"
  },
  "get-uri": {
    "basic-ftp": "5.3.1"
  },
  "pac-proxy-agent": {
    "basic-ftp": "5.3.1"
  },
  "proxy-agent": {
    "basic-ftp": "5.3.1"
  }
}

This is the critical security improvement. Even though the application might not directly depend on basic-ftp, packages like firebase-tools, get-uri, pac-proxy-agent, and proxy-agent do. These transitive dependencies might declare older versions of basic-ftp in their own package.json files.

The overrides field in npm (available in npm 8.3.0+) forces all these packages to use the patched version 5.3.1, regardless of what their individual package.json files specify. This prevents a situation where:

Your app  firebase-tools  basic-ftp 5.1.0 (vulnerable!)

Without overrides, you'd need to wait for firebase-tools to update their basic-ftp dependency, which could take weeks or months. With overrides, the fix is immediate.

How basic-ftp 5.3.1 Prevents the Attack

In version 5.3.1, the basic-ftp library implements proper path validation:

  1. Canonical path resolution: Converts paths like ../../../src/app.js to their absolute, canonical form
  2. Boundary verification: Ensures the resolved path remains within the intended directory (e.g., ./uploads/)
  3. Rejection of traversal sequences: Blocks or sanitizes dangerous patterns like ../, ..\\, and absolute paths

The exact implementation in basic-ftp 5.3.1 likely includes logic similar to:

// Conceptual fix in basic-ftp 5.3.1
const path = require('path');

function validateFilePath(filename, baseDir) {
  // Resolve to absolute path
  const resolvedPath = path.resolve(baseDir, filename);
  const resolvedBase = path.resolve(baseDir);

  // Ensure resolved path is within baseDir
  if (!resolvedPath.startsWith(resolvedBase + path.sep) && resolvedPath !== resolvedBase) {
    throw new Error(`Path traversal detected: ${filename}`);
  }

  return resolvedPath;
}

Now, if an attacker provides ../../../src/app.js, the validation would:

  1. Resolve it: /absolute/path/to/src/app.js
  2. Check if it's within /absolute/path/to/uploads/: NO
  3. Reject the request with an error

Prevention & Best Practices

For Developers Using FTP Libraries

  1. Always validate file paths: Never trust filenames from external sources (FTP servers, user uploads, API parameters)

  2. Use path resolution and boundary checking:
    ```javascript
    const path = require('path');
    const fs = require('fs');

function safeDownload(filename, baseDir) {
const resolved = path.resolve(baseDir, filename);
const base = path.resolve(baseDir);

 if (!resolved.startsWith(base)) {
   throw new Error('Invalid path');
 }

 return resolved;

}
```

  1. Keep dependencies updated: Regularly run npm audit and update vulnerable packages
    bash npm audit npm update

  2. Use security scanning tools: Integrate Snyk, Trivy, or similar tools into your CI/CD pipeline to catch vulnerable dependencies before they reach production

  3. Implement dependency overrides: When transitive dependencies have vulnerabilities, use npm overrides to enforce patched versions across your entire dependency tree

Security Standards & References

Tools for Detection

  • Semgrep: Detects path traversal patterns and unsafe file operations
  • Trivy: Container and dependency scanner that identified CVE-2026-27699
  • npm audit: Built-in vulnerability scanner for Node.js projects
  • Snyk: Continuous security monitoring for open source dependencies

Key Takeaways

  • Path traversal in basic-ftp 5.1.0 allowed attackers to overwrite arbitrary files by injecting ../ sequences into filenames, bypassing directory restrictions
  • The fix (upgrading to 5.3.1) implements canonical path resolution and boundary validation, ensuring that file operations cannot escape the intended directory
  • Transitive dependencies are a critical attack surface: The vulnerability existed not just in direct dependencies but in packages like firebase-tools, get-uri, pac-proxy-agent, and proxy-agent
  • npm overrides are essential for supply chain security: Without them, you'd be blocked waiting for upstream packages to update their dependencies
  • Always validate external input in file operations: Never assume that filenames, paths, or URLs from external sources are safe; always canonicalize and verify boundaries

How Orbis AppSec Detected This

Source: File path input from FTP operations in basic-ftp library functions

Sink: File write operations in basic-ftp 5.1.0 that process user-supplied filenames without proper validation

Missing control: The vulnerable version lacked canonical path resolution and boundary verification to ensure file operations remained within intended directories

CWE: CWE-22 (Improper Limitation of a Pathname to a Restricted Directory)

Fix: Upgrade basic-ftp from 5.1.0 to 5.3.1 and enforce this version across all transitive dependencies using npm overrides

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-27699 demonstrates how a seemingly small validation gap in a file operation can become a critical security vulnerability affecting entire supply chains. The path traversal flaw in basic-ftp 5.1.0 could have allowed attackers to overwrite application code, configuration files, or system files, leading to remote code execution or data corruption.

The fix—upgrading to version 5.3.1 and enforcing this version across transitive dependencies—is straightforward but essential. More importantly, it highlights the importance of:

  • Treating file path validation seriously: Always canonicalize paths and verify boundaries
  • Managing transitive dependencies: Use npm overrides to enforce security fixes across your entire dependency tree
  • Staying vigilant with security updates: Regularly audit dependencies and integrate security scanning into your CI/CD pipeline

By understanding how this vulnerability worked and how the fix eliminates it, you're better equipped to spot similar issues in your own code and make your applications more resilient to path traversal attacks.


References

Frequently Asked Questions

What is path traversal?

Path traversal (directory traversal) is a vulnerability where an attacker manipulates file paths using sequences like `../` or absolute paths to access files outside the intended directory, potentially reading, writing, or deleting sensitive files.

How do you prevent path traversal in Node.js FTP operations?

Always validate and sanitize file paths by: (1) rejecting paths containing `../`, `..\\`, or absolute paths, (2) resolving paths to their canonical form and verifying they remain within the intended directory, (3) using path libraries that enforce restrictions, and (4) keeping dependencies updated.

What CWE is path traversal?

Path traversal is classified as CWE-22 (Improper Limitation of a Pathname to a Restricted Directory), one of the most common and dangerous vulnerability classes affecting file operations.

Is input validation alone enough to prevent path traversal?

No. Simple blacklisting of `../` can be bypassed using URL encoding (`..%2f`), double encoding, or OS-specific alternatives. The best approach combines strict whitelist validation, canonical path resolution, and verification that resolved paths remain within allowed directories.

Can static analysis detect path traversal?

Yes. Modern static analysis tools like Semgrep, Snyk, and Trivy can detect path traversal by tracking tainted data from user input to file operations, identifying missing path validation checks, and flagging dangerous library versions.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #21

Related Articles

critical

How Command Injection Vulnerabilities Happen in Python Subprocess Calls and How to Fix Them

A critical command injection vulnerability was discovered in `src/unused/server/fft.py` where external binaries like `oggenc` and `cocoa_text` were executed with file path parameters that could be manipulated by user input. Although `shell=False` was used, the lack of input validation allowed attackers to potentially trigger processing of arbitrary files or cause denial of service. This fix implements proper path validation to prevent exploitation.

critical

How Path Traversal happens in Node.js Express servers and how to fix it

A path traversal vulnerability in `src/server.js` allowed attackers to escape the intended wiki directory by sending encoded traversal sequences through the `/api/pages/:slug(*)` wildcard endpoint. The flawed `startsWith` boundary check could be bypassed after `decodeURIComponent` processing, potentially exposing arbitrary files on the server. The fix replaces the inline filesystem logic with a dedicated `readWikiPage()` function that enforces proper path validation.

high

How unrestricted file upload via extension-only validation happens in Deno/JavaScript and how to fix it

The review image upload handler in this Deno-based app trusted the client-supplied filename extension to decide whether a file was a "safe" image, without ever inspecting the actual file bytes. The fix adds magic-byte signature verification for PNG, JPEG, GIF, and WEBP formats before the file is written to disk, closing the door on disguised executables and malicious payloads.

critical

How Path Traversal happens in Node.js decompress and how to fix it

A critical zip-slip vulnerability (CVE-2026-53486) in the `@xhmikosr/decompress` package allowed crafted archives to write files outside the intended extraction directory, enabling arbitrary file read/write on the host. The fix upgrades `@xhmikosr/decompress` from 5.0.0 to 10.2.1/11.1.3 and its dependency `@xhmikosr/bin-wrapper` from ^5.0.0 to ^13.2.0, closing the path-sanitization gap in the underlying extractors.

high

How Path Traversal Vulnerabilities Happen in Python File Handling and How to Fix Them

A path traversal vulnerability was discovered in `tools/ardy/setup-text-encoder.py` at line 163, where user-controlled input was passed directly to `open()` without validation. This flaw could allow attackers to read sensitive files outside the intended directory. The fix adds strict path validation to ensure only legitimate files are accessed.

critical

How Missing Authentication on DELETE Endpoints Happens in Python aiohttp and How to Fix It

A critical missing authentication vulnerability in `pz_minimax.py` allowed any network-connected user to delete stored MiniMax prompts via the `DELETE /pz_easyuse/minimax-prompts/{index}` endpoint without any access control. An attacker could enumerate sequential indices to wipe all user-created prompts from the shared JSON file. The fix restricts the DELETE endpoint to localhost-only requests by checking `request.remote` against loopback addresses.