octobercms/october · error · ApplicationException

File not found

Error message

File not found

What it means

ThemeExport::download($name) only accepts internal tokens matching ^oc[0-9a-z]*$ - the uniqid('oc') names export() generates. A mismatch means the caller passed something other than a fresh export token (a display filename, an edited/truncated value, or an injected path). The regex doubles as a path-traversal guard: dots, slashes, and separators are all rejected.

Source

Thrown at modules/cms/models/ThemeExport.php:152

            }

            if (strlen($zipPath) && File::isFile($zipPath)) {
                File::delete($zipPath);
            }

            throw $ex;
        }

        return $zipName;
    }

    /**
     * download
     */
    public static function download($name, $outputName = null)
    {
        if (!preg_match('/^oc[0-9a-z]*$/i', $name)) {
            throw new ApplicationException('File not found');
        }

        $zipPath = temp_path() . '/' . $name;
        if (!file_exists($zipPath)) {
            throw new ApplicationException('File not found');
        }

        $headers = Response::download($zipPath, $outputName)->headers->all();
        $result = Response::make(File::get($zipPath), 200, $headers);

        @File::delete($zipPath);

        return $result;
    }
}

View on GitHub (pinned to b608633a7e)

Solutions

  1. Pass the exact string returned by ThemeExport::export() as $name; use the second parameter $outputName for the user-facing filename.
  2. If the token came from a request, verify it was not truncated or altered (URL-encoding, escaping); regenerate the export rather than massaging the token.
  3. Treat regex failure as a bad request - do not normalize the input to fit the pattern.

Example fix

// before: display filename passed as the token - fails ^oc[0-9a-z]*$
ThemeExport::download('my-theme-export.zip');

// after: internal token for $name, pretty name for $outputName
$token = ThemeExport::export($theme, $data);   // e.g. 'oc64f1a2b3c4d5'
return ThemeExport::download($token, 'my-theme-export.zip');
Defensive patterns

Strategy: validation

Validate before calling

if (!preg_match('/^oc[0-9a-z]*$/i', $name)) {
    // reject with 400 before calling ThemeExport::download()
    abort(400, 'Invalid export token');
}

Type guard

function isValidThemeExportToken(string $name): bool
{
    return (bool) preg_match('/^oc[0-9a-z]*$/i', $name);
}

Try / catch

try {
    return ThemeExport::download($token, 'theme.zip');
} catch (ApplicationException $e) {
    abort(404); // bad or tampered token - do not echo the path
}

Prevention

When it happens

Trigger: Calling download() with a value that fails the regex: ThemeExport::download('my-theme.zip') (dots), a user-modified ?token= URL containing ../ or slashes, or code that passes the $outputName into $name instead of the token returned by export().

Common situations: Controllers persisting or round-tripping download tokens through user-editable state; URL truncation/HTML-escaping mangling the token; attempts to reuse the pretty filename as the token.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/5ae9f0e60e5e1d97. Report an issue: GitHub.