{"record":{"id":"3a98ee2c31dc43bf","repo":"octobercms/october","slug":"backend-lang-media-type-blocked","errorCode":null,"errorMessage":"backend::lang.media.type_blocked","messagePattern":"backend::lang\\.media\\.type_blocked","errorType":"exception","errorClass":"ApplicationException","httpStatus":null,"severity":"error","filePath":"modules/media/classes/MediaLibrary.php","lineNumber":542,"sourceCode":"            throw new ApplicationException(Lang::get('system::lang.media.invalid_path', compact('path')));\n        }\n\n        return $path;\n    }\n\n    /**\n     * validateExtension enforces the Media Library extension allow-list on a destination\n     * path. Every write entry point should pass through here so callers cannot drop a file\n     * with an arbitrary extension into the public media folder.\n     */\n    public static function validateExtension(string $path): void\n    {\n        $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));\n\n        $allowedFileTypes = FileDefinitions::get('default_extensions');\n\n        if (!in_array($extension, $allowedFileTypes)) {\n            throw new ApplicationException(Lang::get('backend::lang.media.type_blocked'));\n        }\n\n        if (System::checkSafeMode() && in_array($extension, ['less', 'sass', 'scss'])) {\n            throw new ApplicationException(Lang::get('backend::lang.media.type_blocked'));\n        }\n    }\n\n    /**\n     * url is a helper that makes a URL for a media file.\n     * Ideally the file should be passed as a string but it will try to deal with anything.\n     * @param string $file\n     * @return string\n     */\n    public static function url($file)\n    {\n        if (is_array($file)) {\n            $file = array_first($file);\n        }","sourceCodeStart":524,"sourceCodeEnd":560,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/media/classes/MediaLibrary.php#L524-L560","documentation":"MediaLibrary::validateExtension() enforces the extension allow-list from FileDefinitions::get('default_extensions') on every write into the media library. A path whose (lowercased) extension is not in that list — .php, .html, .psd, .heic, or a file with no extension at all — throws backend::lang.media.type_blocked. The docblock is explicit: all write entry points funnel through here so nothing with an arbitrary extension lands in the public media folder.","triggerScenarios":"Uploading or renaming to an extension outside default_extensions; requests attempting to drop a .php/.phtml file into the public media folder; newer formats (avif, heic) absent from the active definitions; extensionless target names.","commonSituations":"Users uploading modern image formats the site's definitions predate; attackers probing for executable uploads; custom file_definitions config that trimmed the list; plugin code calling putFile/write without checking the list first.","solutions":["Upload/rename to a whitelisted extension — inspect FileDefinitions::get('default_extensions') to see the live list","Extend the allow-list in the file definitions config if the format is genuinely needed","Convert assets (avif→jpg/png) or bundle unsupported types as zip if policy forbids the extension","For custom media writes, call MediaLibrary::validateExtension($path) yourself before writing so the rejection is intentional, not a 500"],"exampleFix":"// config/filedefinitions.php — before\n'default_extensions' => ['jpg','jpeg','png','gif','svg','webp'],\n\n// after — add the formats your users actually need\n'default_extensions' => ['jpg','jpeg','png','gif','svg','webp','avif','heic'],","handlingStrategy":"validation","validationCode":"$ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));\nif (!in_array($ext, FileDefinitions::get('default_extensions'), true)) {\n    // reject before the write; the server list is authoritative\n    return Response::json(['error' => 'Extension not permitted: '.$ext], 422);\n}","typeGuard":null,"tryCatchPattern":"try {\n    MediaLibrary::validateExtension($destPath);\n} catch (ApplicationException $e) {\n    // handle policy rejection without attempting the write\n    Log::notice('Blocked media write: '.$destPath);\n    throw $e;\n}","preventionTips":["Call MediaLibrary::validateExtension() yourself before custom writes into the media folder","Keep the default_extensions list under review when new formats become mainstream","Restrict the uploader's accepted extensions to the same list"],"tags":["media","file-extension","allow-list","security","upload"],"backgroundTag":"file-extension-not-allowed","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}