security

SSRF, Path Traversal, File Inclusion, And Command Injection

Several serious vulnerabilities appear when untrusted text is treated as a URL, filesystem path, PHP include target, or shell command. Each interpreter boundary needs a narrow allow-list and a design that avoids passing raw user input into powerful APIs.

Core Controls

  • Allow-list remote hosts and schemes before server-side HTTP requests.
  • Resolve file access beneath a controlled base directory and reject traversal attempts.
  • Never use request data to choose a PHP file to include.
  • Avoid shell commands where a PHP API exists; otherwise pass fixed commands and escaped arguments.
  • Block access to internal metadata services and private network destinations when fetching URLs.

Validate Remote Destinations

For a server-side HTTP request, parse the URL and allow only the schemes and hosts the feature genuinely needs.

PHP example
<?php

declare(strict_types=1);

function allowedImportUrl(string $url): bool
{
    $parts = parse_url($url);

    return is_array($parts)
        && ($parts['scheme'] ?? '') === 'https'
        && in_array($parts['host'] ?? '', ['files.example.com'], true);
}

var_dump(allowedImportUrl('https://files.example.com/import.csv'));
var_dump(allowedImportUrl('http://169.254.169.254/latest/meta-data'));

// Prints:
// bool(true)
// bool(false)

An allow-listed hostname is only one layer. Production fetchers may also need DNS and redirect checks so a permitted-looking request cannot reach a private address after resolution or redirection.

Keep Files Beneath A Controlled Directory

When a route downloads a known stored file, map an application identifier to a server-owned path. Do not accept an arbitrary filesystem path from the client.

Use realpath() carefully when checking existing files and verify that the resolved path remains under the intended base directory. For new files, generate the storage name yourself.

Avoid Dynamic Includes And Shell Commands

Never choose a PHP include file from raw request data. Map accepted page or report names to fixed code-owned files.

Prefer PHP APIs for filesystem, archive, and image work. If a shell command is unavoidable, keep the executable fixed, pass narrowly validated arguments, and review the process API carefully. Escaping is not a reason to accept arbitrary commands.

In Application Work

Review image importers, webhook testers, PDF generators, download routes, archive extraction, and admin diagnostics. These often look like utility features but reach sensitive network or filesystem boundaries.

Test rejected cases explicitly: private-network URLs, redirect chains, ../ paths, absolute paths, null bytes, unsupported schemes, and filenames containing shell metacharacters.

What To Check

Before moving on, make sure you can distinguish SSRF, path traversal, file inclusion, and command injection; keep powerful destinations code-owned; and test both allowed and rejected cases.

Practice

Practice: Review A File Import Feature

Requirements

  • List accepted URL schemes and hosts.
  • Reject private-network fetches and path traversal.
  • Keep includes and executable names fixed in code.
  • Describe rejected test cases.
Show solution

Review Points

  • Allow-list remote hosts and schemes before server-side HTTP requests.
  • Resolve file access beneath a controlled base directory and reject traversal attempts.
  • Never use request data to choose a PHP file to include.
  • Avoid shell commands where a PHP API exists; otherwise pass fixed commands and escaped arguments.
  • Block access to internal metadata services and private network destinations when fetching URLs.