{"record":{"id":"f82cd75b43b826df","repo":"octobercms/october","slug":"invalid-image-file-name","errorCode":null,"errorMessage":"Invalid image file name.","messagePattern":"Invalid image file name\\.","errorType":"validation","errorClass":"SystemException","httpStatus":null,"severity":"error","filePath":"modules/media/widgets/MediaManager.php","lineNumber":1916,"sourceCode":"     * @param string $imageSrcPath\n     * @param array $selectionData\n     * @param string $cropSessionKey\n     * @param string $path\n     * @return array\n     */\n    protected function cropImage($imageSrcPath, $selectionData, $cropSessionKey, $path)\n    {\n        $originalFileName = basename($path);\n\n        $path = rtrim(dirname($path), '/').'/';\n        $fileName = basename($imageSrcPath);\n\n        if (\n            strpos($fileName, '..') !== false ||\n            strpos($fileName, '/') !== false ||\n            strpos($fileName, '\\\\') !== false\n        ) {\n            throw new SystemException('Invalid image file name.');\n        }\n\n        $selectionParams = ['x', 'y', 'w', 'h'];\n\n        foreach ($selectionParams as $paramName) {\n            if (!array_key_exists($paramName, $selectionData)) {\n                throw new SystemException('Invalid selection data.');\n            }\n\n            if (!is_numeric($selectionData[$paramName])) {\n                throw new SystemException('Invalid selection data.');\n            }\n\n            $selectionData[$paramName] = (int) $selectionData[$paramName];\n        }\n\n        $sessionDirectoryPath = $this->getCropSessionDirPath($cropSessionKey);\n        $fullSessionDirectoryPath = temp_path($sessionDirectoryPath);","sourceCodeStart":1898,"sourceCodeEnd":1934,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/media/widgets/MediaManager.php#L1898-L1934","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ndata: { image: '/uploads/tmp/crop/original.jpg', ... }\n\n// after\ndata: { image: 'original.jpg', ... }","handlingStrategy":"validation","validationCode":"const name = String(imageSrc).split('/').pop();\nif (name.includes('..') || name.includes('/') || name.includes('\\\\')) {\n    throw new Error('image must be a bare filename');\n}\n$.request('crop', { data: { image: name, ... } });","typeGuard":"function isBareFileName(name) {\n    return typeof name === 'string'\n        && !name.includes('/')\n        && !name.includes('\\\\')\n        && !name.includes('..');\n}","tryCatchPattern":"try {\n    $this->cropImage($src, $selection, $key, $path);\n} catch (\\System\\Classes\\SystemException $e) {\n    if (strpos($e->getMessage(), 'Invalid image file name') !== false) {\n        // treat as a client bug or probe: log and reject, never retry\n        \\Log::warning('Rejected crop source path', ['src' => $src]);\n    }\n    throw $e;\n}","preventionTips":["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."],"tags":["media-manager","crop","path-traversal","security","input-validation"],"backgroundTag":"path-traversal-blocked","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}