gohugoio/hugo · error
alias " " traverses outside the website root directory
Error message
alias "%s" traverses outside the website root directory
What it means
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.
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).
Example fix
--- # before aliases: - "../admin/index" # after aliases: - "old-admin/index" ---
Defensive patterns
Strategy: validation
Validate before calling
func safeAlias(a string) error {
c := path.Clean(filepath.ToSlash(a))
if strings.Split(c, "/")[0] == ".." { return fmt.Errorf("traversal") }
return nil
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- alias " " resolves to website root directory
- alias "" is an empty string
- cannot create " ": Windows filename restriction
- archetype directory ( ) not supported
- contentNodeToContentNodesPage: unexpected type %T
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/ff70b4cd36a962a1.
Report an issue: GitHub.
Appendix: source
Thrown at hugolib/alias.go:139
}
func (a aliasHandler) targetPathAlias(src string, of output.Format) (string, error) {
originalAlias := src
if len(src) <= 0 {
return "", fmt.Errorf("alias \"\" is an empty string")
}
alias := path.Clean(filepath.ToSlash(src))
if !a.allowRoot && alias == "/" {
return "", fmt.Errorf("alias \"%s\" resolves to website root directory", originalAlias)
}
components := strings.Split(alias, "/")
// Validate against directory traversal
if components[0] == ".." {
return "", fmt.Errorf("alias \"%s\" traverses outside the website root directory", originalAlias)
}
// Handle Windows file and directory naming restrictions
// See "Naming Files, Paths, and Namespaces" on MSDN
// https://msdn.microsoft.com/en-us/library/aa365247%28v=VS.85%29.aspx?f=255&MSPPError=-2147217396
msgs := []string{}
reservedNames := []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"}
if strings.ContainsAny(alias, ":*?\"<>|") {
msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains invalid characters on Windows: : * ? \" < > |", originalAlias))
}
for _, ch := range alias {
if ch < ' ' {
msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains ASCII control code (0x00 to 0x1F), invalid on Windows: : * ? \" < > |", originalAlias))
continue
}
}
for _, comp := range components {View on GitHub (pinned to 52c9bd7908)