octobercms/october · error · SystemException
Invalid image file name.
Error message
Invalid image file name.
What it means
SystemException thrown at the top of cropImage() (MediaManager.php:1916) when basename($imageSrcPath) contains '..', '/', or '\\'. This is a path-traversal guard: the crop API is only allowed to operate on a bare filename inside the current crop session directory, never on a path or a traversal sequence.
Source
Thrown at modules/media/widgets/MediaManager.php:1916
* @param string $imageSrcPath
* @param array $selectionData
* @param string $cropSessionKey
* @param string $path
* @return array
*/
protected function cropImage($imageSrcPath, $selectionData, $cropSessionKey, $path)
{
$originalFileName = basename($path);
$path = rtrim(dirname($path), '/').'/';
$fileName = basename($imageSrcPath);
if (
strpos($fileName, '..') !== false ||
strpos($fileName, '/') !== false ||
strpos($fileName, '\\') !== false
) {
throw new SystemException('Invalid image file name.');
}
$selectionParams = ['x', 'y', 'w', 'h'];
foreach ($selectionParams as $paramName) {
if (!array_key_exists($paramName, $selectionData)) {
throw new SystemException('Invalid selection data.');
}
if (!is_numeric($selectionData[$paramName])) {
throw new SystemException('Invalid selection data.');
}
$selectionData[$paramName] = (int) $selectionData[$paramName];
}
$sessionDirectoryPath = $this->getCropSessionDirPath($cropSessionKey);
$fullSessionDirectoryPath = temp_path($sessionDirectoryPath);View on GitHub (pinned to b608633a7e)
Solutions
- In custom clients, post only the file name portion: image = imageSrcPath.split('/').pop().
- Do not attempt to bypass the guard — stage the file via the popup open step first, then crop by bare filename.
- For pentest findings, treat this as the control working as designed; ensure the endpoint stays behind media permission checks.
Example fix
// before
data: { image: '/uploads/tmp/crop/original.jpg', ... }
// after
data: { image: 'original.jpg', ... } Defensive patterns
Strategy: validation
Validate before calling
const name = String(imageSrc).split('/').pop();
if (name.includes('..') || name.includes('/') || name.includes('\\')) {
throw new Error('image must be a bare filename');
}
$.request('crop', { data: { image: name, ... } }); Type guard
function isBareFileName(name) {
return typeof name === 'string'
&& !name.includes('/')
&& !name.includes('\\')
&& !name.includes('..');
} Try / catch
try {
$this->cropImage($src, $selection, $key, $path);
} catch (\System\Classes\SystemException $e) {
if (strpos($e->getMessage(), 'Invalid image file name') !== false) {
// treat as a client bug or probe: log and reject, never retry
\Log::warning('Rejected crop source path', ['src' => $src]);
}
throw $e;
} Prevention
- Always derive the crop source from the previous server response, never from a URL or DOM path.
- Treat this exception as a security signal — investigate the source of the request.
When it happens
Trigger: Posting image='../../storage/app/...' , image='sub/dir/original.png', or any absolute path as the crop source. Legit stock clients always send the plain staged filename ('original.jpg' / 'resized-W-H.jpg'), so this almost always indicates a hand-crafted request or a broken custom client.
Common situations: Security scanners probing the crop endpoint; custom crop UI that echoes back a full URL or DOM path instead of the staged file name; middleware/tests that forward the whole src URL.
Related errors
- Invalid selection data.
- cms::lang.cms_object.invalid_file
- File not found
- editor::lang.filesystem.error_deleting_directory
- The file type used is blocked for security reasons.
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/f82cd75b43b826df.
Report an issue: GitHub.