Course contentsShow
← Node.js
Lesson 1795 of 1,98016. Security Hardening and Threat MitigationFree lesson

Safe File System Access Patterns

Restrict file path resolution to prevent traversal attacks through user-controlled input.

In this lesson, you will learn how to enforce strict path boundaries to prevent Directory Traversal attacks when handling user-provided file paths in your Node.js applications.

The Danger of Unrestricted Paths

When your application accepts a file path from a user—such as a filename in an API request—it is critical to remember that path.join and fs operations do not automatically restrict the scope of the file system. If a user provides a value like ../../../../etc/passwd, a naive implementation will resolve that path outside your intended directory, granting the attacker access to sensitive system files.

Establishing a Rooted Boundary

To defend against this, you must "jail" your file operations to a specific root directory. The most robust approach involves resolving both the intended root path and the final user-provided path to their absolute forms, then verifying that the resolved path still starts with the root path string.

Consider this implementation pattern:

const path = require('path');
const fs = require('fs');

const PUBLIC_ROOT = path.resolve('./public-files');

function getSafeFilePath(userRequestedPath) {
  // 1. Join and resolve the path
  const targetPath = path.resolve(PUBLIC_ROOT, userRequestedPath);

  // 2. Verify the prefix matches the root
  if (!targetPath.startsWith(PUBLIC_ROOT)) {
    throw new Error('Security Violation: Attempted directory traversal.');
  }

  return targetPath;
}

Why This Works

By using path.resolve(), you resolve all .. segments and symbolic links into an absolute string representation. The startsWith check acts as a logical barrier. Even if an attacker attempts to break out of the public-files folder, the resulting targetPath will have a prefix that differs from PUBLIC_ROOT, allowing you to catch and reject the request before any sensitive IO operations occur.

Remember that input validation—as we discussed in previous lessons—is your first line of defense. However, even if an attacker bypasses basic sanitization, this structural boundary ensures that the file system cannot be traversed beyond the scope you have defined.

Key Takeaway: Always resolve paths to absolute strings and verify that the target path still resides within the designated root directory before performing any file system operations.