Skip to content

Security: Path Traversal in System Log Download/Clear endpoints #194

@lighthousekeeper1212

Description

@lighthousekeeper1212

Summary

The system log download and clear endpoints are vulnerable to path traversal via unsanitized filename parameter. The getFilePath() method in SystemLogs.php concatenates the base log path with user-supplied filename without sanitizing directory traversal sequences.

Affected Code

File: src/Support/SystemLogs.php - getFilePath(string $name)

public function getFilePath(string $name): string
{
    return $this->basePathForLogs() . $name;  // No sanitization
}

Validation in DownloadSystemLog.php and ClearSystemLog.php:

'filename' => ['required', 'string', 'max:255']  // Missing path traversal protection

Impact

An authenticated user can:

  1. Download arbitrary files readable by the web server (e.g., .env with database credentials, APP_KEY)
  2. Clear/truncate arbitrary files writable by the web server via fopen($filePath, 'w+')

The APP_KEY leak can lead to RCE via Laravel's encrypted cookie deserialization.

Secure Comparison

The logs() method in the same class correctly uses glob('*.log') + realpath() to enumerate only actual log files. The download/clear endpoints should validate against this enumerated list.

Suggested Fix

Apply basename() to strip directory components, and validate the resolved path is within the logs directory:

public function getFilePath(string $name): string
{
    $safeName = basename($name);
    $filePath = $this->basePathForLogs() . $safeName;
    
    $realPath = realpath($filePath);
    $baseReal = realpath($this->basePathForLogs());
    
    if ($realPath === false || !str_starts_with($realPath, $baseReal)) {
        throw new \InvalidArgumentException('Invalid filename');
    }
    
    return $realPath;
}

Or add a regex validation rule: 'regex:/^[a-zA-Z0-9.\-_]+$/'

Additional Note

A secondary issue exists in MediaDownloadExternal.php where isPublicDomainUrl() validates URLs by checking if the host is a raw IP but does not resolve DNS to check for private IP ranges, allowing DNS rebinding SSRF.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions