Sitelet https://github.com/processwire/processwire-issues/issues/2353
Skip to content

WireFileTools::render() rejects valid files on Windows: allowedPaths is normalized, $filename is not #2353

Description

@matjazpotocnik

WireFileTools::render() normalizes the target filename to unix slashes, but compares it against the allowedPaths without normalizing those. On Windows a caller that builds an allowed path from __DIR__ gets backslashes, so the prefix comparison fails and a valid file is rejected with a WireFilesException.

The sibling method include() does not have this bug: it delegates the check to fileInPath(), which normalizes both sides.

Steps to reproduce

$dir = __DIR__;                        // C:\path\to   (backslashes on Windows)
$wire->files->render(
    $dir . '/target.php',              // the standard PW idiom
    [],
    ['allowedPaths' => [$dir . '/']]   // same directory, so it must be allowed
);

Expected: the file renders.

Actual:

ProcessWire\WireFilesException: render: Filename C:/path/to/target.php is not in
an allowed path. Paths: C:\path\to/

Root cause

wire/core/WireFileTools/WireFileTools.php, render():

$options = array_merge($defaults, $options);
$filename = $this->unixFileName($filename);     //  forward slashes
...
} else if(strpos($filename, '/') !== false) {
    // filename is absolute, make sure it's in a location we consider safe
    $allowed = false;
    foreach($options['allowedPaths'] as $path) {        
        if(strpos($filename, $path) === 0) {           

$filename goes through unixFileName(); $path does not. On Windows __DIR__ yields \, so strpos($filename, $path) === 0 can never be true for a __DIR__-derived entry.

Suggested fix

Normalize allowedPaths in the same place the filename is normalized.

--- a/wire/core/WireFileTools/WireFileTools.php
+++ b/wire/core/WireFileTools/WireFileTools.php
@@ -1621,6 +1621,10 @@ class WireFileTools extends Wire {
 		$options = array_merge($defaults, $options);
 		$filename = $this->unixFileName($filename);
 
+		foreach($options['allowedPaths'] as $key => $allowedPath) {
+			$options['allowedPaths'][$key] = $this->unixDirName($allowedPath);
+		}
+
 		// add .php extension if filename doesn't already have an extension
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions