{"record":{"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/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/hugolib/alias.go#L121-L157","documentation":"Returned by targetPathAlias when the first path component of the cleaned alias is \"..\", i.e. the alias attempts directory traversal outside the publish root. This is a security guard: aliases are written to the publish directory and a \"..\" prefix would escape it, allowing arbitrary file overwrite. Always fatal regardless of allowRoot.","triggerScenarios":"A front-matter aliases entry beginning with \"../\" or resolving so that components[0] == \"..\" after path.Clean — e.g. aliases: [\"../secret\"], aliases: [\"..%2f..\" ] after decoding, or a malicious/admin-supplied alias string reaching publishDestAlias.","commonSituations":"Copy-pasted alias from an external source containing a relative-up path; user-supplied content (CMS, comments rendered into front matter) attempting path escape; misconfigured redirect generator concatenating user input without sanitization.","solutions":["Remove the leading \"..\" from the alias; aliases must be site-relative paths under the publish root.","Sanitize any user/external input destined for aliases: reject entries whose cleaned form starts with \"..\".","Run a security review if aliases are populated from untrusted input (this is a path-traversal vector)."],"exampleFix":"---\n# before\naliases:\n  - \"../admin/index\"\n# after\naliases:\n  - \"old-admin/index\"\n---","handlingStrategy":"validation","validationCode":"func safeAlias(a string) error {\n    c := path.Clean(filepath.ToSlash(a))\n    if strings.Split(c, \"/\")[0] == \"..\" { return fmt.Errorf(\"traversal\") }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat aliases as untrusted input: reject any whose cleaned form starts with '..'.","Never concatenate user input into aliases without sanitization.","Lint front matter for '..' alias components."],"tags":["alias","security","path-traversal","hugolib"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}