{"id":"ff70b4cd36a962a1","repo":"gohugoio/hugo","slug":"alias-s-traverses-outside-the-website-root-dire","errorCode":null,"errorMessage":"alias \"%s\" traverses outside the website root directory","messagePattern":"alias \"(.+?)\" traverses outside the website root directory","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hugolib/alias.go","lineNumber":139,"sourceCode":"}\n\nfunc (a aliasHandler) targetPathAlias(src string, of output.Format) (string, error) {\n\toriginalAlias := src\n\tif len(src) <= 0 {\n\t\treturn \"\", fmt.Errorf(\"alias \\\"\\\" is an empty string\")\n\t}\n\n\talias := path.Clean(filepath.ToSlash(src))\n\n\tif !a.allowRoot && alias == \"/\" {\n\t\treturn \"\", fmt.Errorf(\"alias \\\"%s\\\" resolves to website root directory\", originalAlias)\n\t}\n\n\tcomponents := strings.Split(alias, \"/\")\n\n\t// Validate against directory traversal\n\tif components[0] == \"..\" {\n\t\treturn \"\", fmt.Errorf(\"alias \\\"%s\\\" traverses outside the website root directory\", originalAlias)\n\t}\n\n\t// Handle Windows file and directory naming restrictions\n\t// See \"Naming Files, Paths, and Namespaces\" on MSDN\n\t// https://msdn.microsoft.com/en-us/library/aa365247%28v=VS.85%29.aspx?f=255&MSPPError=-2147217396\n\tmsgs := []string{}\n\treservedNames := []string{\"CON\", \"PRN\", \"AUX\", \"NUL\", \"COM0\", \"COM1\", \"COM2\", \"COM3\", \"COM4\", \"COM5\", \"COM6\", \"COM7\", \"COM8\", \"COM9\", \"LPT0\", \"LPT1\", \"LPT2\", \"LPT3\", \"LPT4\", \"LPT5\", \"LPT6\", \"LPT7\", \"LPT8\", \"LPT9\"}\n\n\tif strings.ContainsAny(alias, \":*?\\\"<>|\") {\n\t\tmsgs = append(msgs, fmt.Sprintf(\"Alias \\\"%s\\\" contains invalid characters on Windows: : * ? \\\" < > |\", originalAlias))\n\t}\n\tfor _, ch := range alias {\n\t\tif ch < ' ' {\n\t\t\tmsgs = append(msgs, fmt.Sprintf(\"Alias \\\"%s\\\" contains ASCII control code (0x00 to 0x1F), invalid on Windows: : * ? \\\" < > |\", originalAlias))\n\t\t\tcontinue\n\t\t}\n\t}\n\tfor _, comp := range components {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/hugolib/alias.go#L121-L157","documentation":"After cleaning the alias path, Hugo splits it into components and rejects it if the first component is \"..\", meaning the alias would place a redirect file outside the publish (website root) directory. This is a directory-traversal guard: alias values come from content front matter and must never cause writes above publishDir.","triggerScenarios":"Front matter like `aliases: [\"../old-page\"]` or a relative alias with enough `..` segments that path.Clean leaves a leading \"..\", e.g. `aliases: [\"foo/../../bar\"]`. Fires in aliasHandler.targetPathAlias during publishing of alias files.","commonSituations":"Authors writing aliases relative to the current page's directory and using `..` to go up a level (aliases are resolved against the site root, not the page); content imported from other systems where redirects were expressed as relative paths; untrusted or generated front matter containing traversal sequences.","solutions":["Rewrite the alias as a root-relative path from the site root, e.g. `aliases: [\"/old-section/old-page/\"]` instead of `../old-page`.","Remove any `..` segments — aliases are always resolved against publishDir, so parent-directory references are never needed.","If migrating redirects in bulk, script a normalization pass that converts relative redirect sources to absolute site paths before writing front matter."],"exampleFix":"# before\n---\naliases: [\"../old-page\"]\n---\n\n# after\n---\naliases: [\"/section/old-page/\"]\n---","handlingStrategy":"validation","validationCode":"func aliasInsideRoot(a string) bool {\n    clean := path.Clean(filepath.ToSlash(a))\n    return !strings.HasPrefix(clean, \"../\") && clean != \"..\" && !strings.Contains(clean, \"/../\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"traverses outside the website root\") {\n    // surface the alias value and its source page; do not retry\n}","preventionTips":["Never use `..` segments in aliases; keep them site-root-relative (e.g. \"/old/path/\")","Sanitize aliases generated from external data (CMS imports) with path.Clean before writing front matter","Add a pre-build check that walks all pages' aliases and rejects traversal patterns"],"tags":["hugo","aliases","path-traversal","front-matter","build"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}