{"record":{"id":"ae1bd804e9584955","repo":"hashicorp/nomad","slug":"alloc-dir-must-be-absolute","errorCode":null,"errorMessage":"alloc dir must be absolute","messagePattern":"alloc dir must be absolute","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/escapingfs/escapes.go","lineNumber":119,"sourceCode":"func hasPrefixCaseInsensitive(path, prefix string) bool {\n\tif len(prefix) > len(path) {\n\t\treturn false\n\t}\n\treturn strings.EqualFold(path[:len(prefix)], prefix)\n}\n\n// PathEscapesAllocDir returns true if base/prefix/path escapes the given base directory.\n//\n// Escaping a directory can be done with relative paths (e.g. ../../ etc.) or by\n// using symlinks. This checks both methods.\n//\n// The base directory must be an absolute path.\nfunc PathEscapesAllocDir(base, prefix, path string) (bool, error) {\n\tfull := filepath.Join(base, prefix, path)\n\n\t// If base is not an absolute path, the caller passed in the wrong thing.\n\tif !filepath.IsAbs(base) {\n\t\treturn false, errors.New(\"alloc dir must be absolute\")\n\t}\n\n\t// Check path does not escape the alloc dir using relative paths.\n\tif escapes, err := PathEscapesAllocViaRelative(prefix, path); err != nil {\n\t\treturn false, err\n\t} else if escapes {\n\t\treturn true, nil\n\t}\n\n\t// Check path does not escape the alloc dir using symlinks.\n\tif escapes, err := pathEscapesBaseViaSymlink(base, full); err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\t// Treat non-existent files as non-errors; perhaps not ideal but we\n\t\t\t// have existing features (log-follow) that depend on this. Still safe,\n\t\t\t// because we do the symlink check on every ReadAt call also.\n\t\t\treturn false, nil\n\t\t}\n\t\treturn false, err","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/escapingfs/escapes.go#L101-L137","documentation":"PathEscapesAllocDir checks whether a path escapes a Nomad allocation directory. It requires the `base` (alloc dir) argument to be an absolute path; if a caller passes a relative base, filepath.Join would produce an unusable relative root and escape detection would be unreliable, so the function fails fast with this error.","triggerScenarios":"Calling helper/escapingfs.PathEscapesAllocDir(base, prefix, path) with a non-absolute `base` value, e.g. \"alloc/\" or \"./alloc\". It is reached indirectly via callers like streamAllocDir (HTTP alloc dir streaming) when the configured client alloc_dir is relative.","commonSituations":"Nomad agent configs with `client { alloc_dir = \"nomad-data\" }` (relative path); manually invoking the helper in tests/tools with a relative base; code constructing the alloc dir from a relative working directory.","solutions":["Set client.alloc_dir in the Nomad agent config to an absolute path (e.g. /opt/nomad/data/alloc) and restart the agent.","If calling PathEscapesAllocDir directly, wrap the base with filepath.Abs() before calling.","Verify downstream callers (e.g. alloc dir HTTP streaming handlers) propagate an absolute dir, not a user-supplied relative one."],"exampleFix":"// before\nescapes, err := PathEscapesAllocDir(\"alloc\", prefix, path)\n// after\nabsBase, err := filepath.Abs(\"alloc\")\nif err != nil { return err }\nescapes, err := PathEscapesAllocDir(absBase, prefix, path)","handlingStrategy":"validation","validationCode":"if !filepath.IsAbs(base) {\n    return fmt.Errorf(\"alloc dir %q must be absolute\", base)\n}\nescapes, err := PathEscapesAllocDir(base, prefix, path)","typeGuard":"func isAbsBase(base string) bool { return filepath.IsAbs(base) }","tryCatchPattern":"escapes, err := PathEscapesAllocDir(base, prefix, path)\nif err != nil {\n    if err.Error() == \"alloc dir must be absolute\" {\n        abs, aerr := filepath.Abs(base)\n        if aerr != nil { return aerr }\n        escapes, err = PathEscapesAllocDir(abs, prefix, path)\n    }\n    if err != nil { return err }\n}","preventionTips":["Always derive the alloc dir from an absolute client data_dir in agent config.","Call filepath.Abs at configuration-load time, not at request time.","Add a startup config check rejecting relative alloc_dir values."],"tags":["filesystem","path-validation","config"],"backgroundTag":"absolute-path-required","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}