Path Utils

Security Functions

Security-focused path resolution and validation functions.

The security functions in @ucdjs/path-utils provide robust protection against path traversal attacks, encoding exploits, and boundary violations.

resolveSafePath

Resolves a path safely within a defined base directory boundary, preventing traversal attacks and malicious inputs.

Signature

function resolveSafePath(basePath: string, inputPath: string): string

Parameters

  • basePath (string) - The base directory that acts as the virtual filesystem root. Must be a non-empty string.
  • inputPath (string) - The path to resolve, which can be relative, absolute, or URL-encoded.

Returns

  • (string) - The safely resolved absolute path within the base directory boundary.

Throws

Behavior

The function implements a virtual filesystem boundary model:

Absolute Paths

Treated as relative to the boundary root:

resolveSafePath('/home/user', '/config.json')
// → '/home/user/config.json'

Root Reference

The root / points to the boundary root:

resolveSafePath('/home/user', '/')
// → '/home/user'

Current Directory

References point to the base path:

resolveSafePath('/home/user', '.')
// → '/home/user'

Security Features

Path Traversal Prevention

Blocks attempts to escape the boundary:

resolveSafePath('/var/www', '../../etc/passwd')
// ❌ PathTraversalError

Encoding Attack Prevention

Detects and blocks encoded traversal:

resolveSafePath('/var/www', '%2e%2e%2fetc%2fpasswd')
// ❌ PathTraversalError

Control Character Filtering

Rejects null bytes and control chars:

resolveSafePath('/base', 'file\0.txt')
// ❌ IllegalCharacterInPathError

UNC Path Rejection

Blocks Windows UNC network paths:

resolveSafePath('C:\\base', '\\\\server\\share')
// ❌ UNCPathNotSupportedError

Examples

Basic Usage

import { resolveSafePath } from '@ucdjs/path-utils';

const boundary = '/var/www/html';

// Relative paths
resolveSafePath(boundary, 'assets/style.css');
// → '/var/www/html/assets/style.css'

// Absolute paths (treated as relative to boundary)
resolveSafePath(boundary, '/images/logo.png');
// → '/var/www/html/images/logo.png'

// Current directory
resolveSafePath(boundary, './index.html');
// → '/var/www/html/index.html'

// Empty input
resolveSafePath(boundary, '');
// → '/var/www/html'

Windows Paths

const boundary = 'C:\\Projects\\MyApp';

// Windows-style paths
resolveSafePath(boundary, 'src\\index.ts');
// → 'C:/Projects/MyApp/src/index.ts'

// Mixed separators
resolveSafePath(boundary, 'src/components\\Button.tsx');
// → 'C:/Projects/MyApp/src/components/Button.tsx'

// Absolute Windows path within boundary
resolveSafePath(boundary, 'C:\\Projects\\MyApp\\data\\db.json');
// → 'C:/Projects/MyApp/data/db.json'

// Different drive letter
resolveSafePath(boundary, 'D:\\external.txt');
// ❌ WindowsDriveMismatchError

URL-Encoded Paths

// Standard encoding
resolveSafePath('/base', 'file%20name.txt');
// → '/base/file name.txt'

// Path encoding
resolveSafePath('/base', 'path%2Fto%2Ffile.txt');
// → '/base/path/to/file.txt'

// Nested encoding
resolveSafePath('/base', '%252Fconfig%252Fjson');
// → '/base/config/json'

decodePathSafely

Safely decodes a URL-encoded path with protection against infinite loops and malicious nested encodings.

Signature

function decodePathSafely(encodedPath: string): string

Parameters

  • encodedPath (string) - The URL-encoded path to decode.

Returns

  • (string) - The fully decoded path.

Throws

Behavior

The function decodes paths iteratively until no more encoding is detected:

  1. Attempts decodeURIComponent()
  2. Manually decodes common encodings:
    • %2e. (dots)
    • %2f/ (forward slashes)
    • %5c\ (backslashes)
  3. Repeats up to 10 iterations maximum
  4. Throws error if limit exceeded (prevents infinite loops from malicious inputs)

Examples

import { decodePathSafely } from '@ucdjs/path-utils';

// Standard URL encoding
decodePathSafely('path%20with%20spaces');
// → 'path with spaces'

// Path separators
decodePathSafely('folder%2Ffile.txt');
// → 'folder/file.txt'

// Nested encoding
decodePathSafely('%252e%252e'); // %25 = %, so %252e = %2e = .
// → '..'

// Mixed encoding
decodePathSafely('file%2Ename%20with%20spaces');
// → 'file.name with spaces'

// Malformed encoding (handled gracefully)
decodePathSafely('%XY%ZZ');
// → '%XY%ZZ'

// Excessive nesting (protection)
decodePathSafely(maliciouslyNestedInput);
// ❌ MaximumDecodingIterationsExceededError

isWithinBase

Checks if a resolved path is within a specified base path, considering case sensitivity and platform-specific behavior.

Signature

function isWithinBase(basePath: string, resolvedPath: string): boolean

Parameters

  • basePath (string) - The base directory boundary to check against.
  • resolvedPath (string) - The path to validate.

Returns

  • (boolean) - true if the resolved path is within the base path, false otherwise.

Behavior

Normalization

Both paths are normalized before comparison to resolve . and .. segments.

Case Sensitivity

Respects filesystem case sensitivity:

  • Linux: case-sensitive
  • Windows/macOS: case-insensitive

Partial Match Prevention

Prevents partial directory matches:

isWithinBase('/root', '/root2/file')
// → false (not /root/*)

Examples

import { isWithinBase } from '@ucdjs/path-utils';

// Exact match
isWithinBase('/home/user', '/home/user');
// → true

// Within boundary
isWithinBase('/home/user', '/home/user/documents/file.txt');
// → true

// Outside boundary
isWithinBase('/home/user', '/home/other/file.txt');
// → false

// Partial match prevention
isWithinBase('/var/log', '/var/log2/file.txt');
// → false

// Normalized paths
isWithinBase('/home/user', '/home/user/../user/docs/file.txt');
// → true

// Windows paths
isWithinBase('C:\\Users\\John', 'C:\\Users\\John\\Documents\\file.txt');
// → true

// Case sensitivity (on case-sensitive systems)
isWithinBase('/home/user', '/home/User/file.txt');
// → false (on Linux)
// → true (on Windows/macOS)

Best Practices

Always use resolveSafePath as your primary function for user-provided paths. It handles decoding, validation, and boundary enforcement automatically.Never trust user input - Always resolve paths through resolveSafePath before using them in file operations, even if they appear safe.Use try-catch blocks to handle errors gracefully and provide appropriate user feedback for security violations.