{"record":{"id":"ccd3b49129f0c598","repo":"octobercms/october","slug":"system-lang-media-invalid-path","errorCode":null,"errorMessage":"system::lang.media.invalid_path","messagePattern":"system::lang\\.media\\.invalid_path","errorType":"exception","errorClass":"ApplicationException","httpStatus":null,"severity":"error","filePath":"modules/media/classes/MediaLibrary.php","lineNumber":500,"sourceCode":"     * @return string\n     */\n    public static function validatePath($path, $normalizeOnly = false): string\n    {\n        $path = str_replace('\\\\', '/', $path);\n        $path = '/'.trim($path, '/');\n\n        if ($normalizeOnly) {\n            return $path;\n        }\n\n        // Reject paths that are not valid UTF-8\n        if (!mb_check_encoding($path, 'UTF-8')) {\n            throw new ApplicationException(Lang::get('system::lang.media.invalid_path_encoding', ['path' => mb_scrub($path)]));\n        }\n\n        // Reject control, format and other invisible characters\n        if (preg_match('/[\\p{C}]/u', $path)) {\n            throw new ApplicationException(Lang::get('system::lang.media.invalid_path', compact('path')));\n        }\n\n        // Reject characters reserved by file systems and URLs\n        if (preg_match('/[<>:\"|?*]/', $path)) {\n            throw new ApplicationException(Lang::get('system::lang.media.invalid_path', compact('path')));\n        }\n\n        $regexDirectorySeparator = preg_quote('/', '#');\n        $regexDot = preg_quote('.', '#');\n        $regex = [\n            // Beginning of path\n            '(^'.$regexDot.'+?'.$regexDirectorySeparator.')',\n\n            // Middle of path\n            '('.$regexDirectorySeparator.$regexDot.'+?'.$regexDirectorySeparator.')',\n\n            // End of path\n            '('.$regexDirectorySeparator.$regexDot.'+?$)',","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/media/classes/MediaLibrary.php#L482-L518","documentation":"MediaLibrary::validatePath() rejects any path containing a Unicode category-C character (preg_match('/[\\p{C}]/u')): control chars 0x00-0x1F and 0x7F-0x9F, format chars like zero-width space (U+200B), BOM (U+FEFF) and bidi/RTL override marks (U+200E, U+202E), plus surrogates and unassigned code points. These characters are invisible in listings but break rendering, sorting, matching, and remote storage keys, so the media library hard-rejects them.","triggerScenarios":"Filenames copy-pasted from web pages, PDFs, or word processors that embed zero-width characters; crafted names using RTL-override to disguise the real extension; paths containing literal tab/newline; a UTF-8 BOM prefixed to the first segment.","commonSituations":"Bulk imports from CSV/Excel with unclean data; user complaints that a file 'looks fine' but the media manager rejects it; security scanners probing with bidi tricks.","solutions":["Strip category-C characters before calling the API: $path = preg_replace('/\\p{C}/u', '', $path);","For user-supplied names, sanitize aggressively on input (slugify or transliterate) instead of accepting raw pasted strings","Paste the path into a hex viewer or use bin2hex() on the suspect segment to identify the exact invisible code point, then rename the file"],"exampleFix":"// before\n$clean = MediaLibrary::validatePath($raw); // rejects zero-width chars\n\n// after\n$raw = preg_replace('/\\p{C}/u', '', $raw);\n$clean = MediaLibrary::validatePath($raw);","handlingStrategy":"validation","validationCode":"$path = preg_replace('/\\p{C}/u', '', $path); // strip control/format/invisible chars\n$clean = MediaLibrary::validatePath($path);","typeGuard":"function hasInvisiblePathChars(string $path): bool {\n    return (bool) preg_match('/\\p{C}/u', $path);\n}","tryCatchPattern":null,"preventionTips":["Slugify user-supplied names on input so invisible characters never enter storage","Audit bulk-import data (CSV/Excel) for zero-width and bidi marks before import","Treat invisible-character payloads as hostile — they often mask extension tricks"],"tags":["media","unicode","invisible-characters","path-validation"],"backgroundTag":"invisible-characters-in-path","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}