{"record":{"id":"1b97ae319024685d","repo":"symfony/http-foundation","slug":"the-filename-and-the-fallback-cannot-contain-the-and","errorCode":null,"errorMessage":"The filename and the fallback cannot contain the \"/\" and \"\\\" characters.","messagePattern":"The filename and the fallback cannot contain the \"/\" and \"\\\\\" characters\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"HeaderUtils.php","lineNumber":187,"sourceCode":"        }\n\n        if ('' === $filenameFallback) {\n            $filenameFallback = $filename;\n        }\n\n        // filenameFallback is not ASCII.\n        if (!preg_match('/^[\\x20-\\x7e]*$/', $filenameFallback)) {\n            throw new \\InvalidArgumentException('The filename fallback must only contain ASCII characters.');\n        }\n\n        // percent characters aren't safe in fallback.\n        if (str_contains($filenameFallback, '%')) {\n            throw new \\InvalidArgumentException('The filename fallback cannot contain the \"%\" character.');\n        }\n\n        // path separators aren't allowed in either.\n        if (str_contains($filename, '/') || str_contains($filename, '\\\\') || str_contains($filenameFallback, '/') || str_contains($filenameFallback, '\\\\')) {\n            throw new \\InvalidArgumentException('The filename and the fallback cannot contain the \"/\" and \"\\\\\" characters.');\n        }\n\n        $params = ['filename' => $filenameFallback];\n        if ($filename !== $filenameFallback) {\n            $params['filename*'] = \"utf-8''\".rawurlencode($filename);\n        }\n\n        return $disposition.'; '.self::toString($params, ';');\n    }\n\n    /**\n     * Like parse_str(), but preserves dots in variable names.\n     */\n    public static function parseQuery(string $query, bool $ignoreBrackets = false, string $separator = '&'): array\n    {\n        $q = [];\n\n        foreach (explode($separator, $query) as $v) {","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/symfony/http-foundation/blob/5aea19cd678fa4140f6108406f1096de5e9ed6e4/HeaderUtils.php#L169-L205","documentation":"Path separators '/' and '\\' are forbidden in both $filename and $filenameFallback to prevent Content-Disposition header values from carrying path components, which would enable header injection / path-traversal style attacks against clients that honor directory parts in the filename. makeDisposition() throws this InvalidArgumentException if either string contains either separator.","triggerScenarios":"Calling makeDisposition($disposition, $filename) or with a fallback where $filename or $filenameFallback contains '/' or '\\' — e.g. 'uploads/report.pdf', 'C:\\\\temp\\\\a.pdf', or a user-supplied '../../etc/passwd' filename.","commonSituations":"Passing a full server-side file path instead of just the basename; echoing unsanitized user upload names (path traversal attempt) into the Content-Disposition header; Windows paths with backslashes.","solutions":["Pass only the basename: HeaderUtils::makeDisposition($d, basename($path))","Strip separators from user input: str_replace(['/', '\\\\'], '', $filename) or preg_replace('#[/\\\\\\\\]#', '_', $name)","Reject requests containing path separators before building the header (defense against traversal)","Wrap in try/catch InvalidArgumentException, sanitize, and retry with the cleaned name"],"exampleFix":"// before\nHeaderUtils::makeDisposition('attachment', '/var/www/uploads/report.pdf'); // throws\n// after\nHeaderUtils::makeDisposition('attachment', basename('/var/www/uploads/report.pdf')); // 'report.pdf'","handlingStrategy":"validation","validationCode":"$name = basename(str_replace('\\\\', '/', $filename));\nif ($name !== $filename) {\n    throw new \\InvalidArgumentException('Filename must not contain path separators.');\n}","typeGuard":"function hasNoPathSeparators(string $s): bool {\n    return !str_contains($s, '/') && !str_contains($s, '\\\\');\n}","tryCatchPattern":"try {\n    $header = HeaderUtils::makeDisposition($disposition, $filename);\n} catch (\\InvalidArgumentException $e) {\n    $header = HeaderUtils::makeDisposition($disposition, basename(str_replace('\\\\', '/', $filename)));\n}","preventionTips":["Always pass basename($path), never a full server path","Treat user-supplied filenames as untrusted: reject or strip '/' and '\\\\' (path-traversal defense)","Log/reject traversal attempts rather than silently sanitizing when input is malicious"],"tags":["php","http-headers","path-traversal","security","symfony"],"backgroundTag":"path-traversal-blocked","analyzedSha":"5aea19cd678fa4140f6108406f1096de5e9ed6e4","analyzedAt":"2026-09-13T01:52:22.855Z","contentChangedAt":"2026-09-13T01:52:22.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}