hashicorp/nomad · critical
archive contains symlink that escapes alloc dir
Error message
archive contains symlink that escapes alloc dir
What it means
Security guard against path traversal during alloc dir migration: if a symlink entry in the tar archive (its name or its target) would resolve outside the allocation directory, Nomad aborts extraction with this error. It protects against malicious or corrupted archives escaping the sandbox.
Source
Thrown at client/allocwatcher/alloc_watcher.go:637
// Can't change owner if not root or on Windows.
if euid == 0 {
if err := os.Chown(name, hdr.Uid, hdr.Gid); err != nil {
return fmt.Errorf("error chowning directory %w", err)
}
}
continue
}
// If the header is for a symlink we create the symlink
if hdr.Typeflag == tar.TypeSymlink {
if err = os.Symlink(hdr.Linkname, filepath.Join(dest, hdr.Name)); err != nil {
return fmt.Errorf("error creating symlink: %w", err)
}
for _, path := range []string{hdr.Name, hdr.Linkname} {
if escapes, err := escapingfs.PathEscapesAllocDir(dest, "", path); err != nil {
return fmt.Errorf("error evaluating symlink: %w", err)
} else if escapes {
return fmt.Errorf("archive contains symlink that escapes alloc dir")
}
}
continue
}
// If the header is a file, we write to a file
if hdr.Typeflag == tar.TypeReg {
fPath := filepath.Join(dest, hdr.Name)
if _, err := os.Lstat(fPath); err == nil {
if err := os.Remove(fPath); err != nil {
return fmt.Errorf("error removing existing file: %w", err)
}
}
f, err := os.Create(fPath)
if err != nil {
return fmt.Errorf("error creating file: %w", err)
}
View on GitHub (pinned to 482b49bf1a)
Solutions
- Find the offending symlink in the previous alloc dir and repoint it inside the alloc dir
- Fix the task to not create symlinks escaping its alloc directory
- Re-snapshot the alloc dir after removing the escaping link, then retry migration
- If migration is not essential, disable it (canonicalize/no migration) and let the new alloc start fresh
Defensive patterns
Strategy: validation
Validate before calling
// Before relying on migration, audit task-created symlinks in the alloc dir: // walk the dir and fail the check if filepath.EvalSymlinks resolves outside the alloc dir root
Type guard
func symlinkEscapes(dest, link, target string) bool {
resolved := filepath.Clean(filepath.Join(dest, link))
return !strings.HasPrefix(resolved, filepath.Clean(dest)+string(os.PathSeparator))
} Try / catch
if err := watcher.Wait(ctx); err != nil {
if strings.Contains(err.Error(), "escapes alloc dir") {
// Security violation: do NOT retry with same data; start fresh alloc
return startWithoutMigration(ctx, alloc)
}
return err
} Prevention
- Ensure tasks only create symlinks within their alloc directory
- Audit shared volume/task configs that produce absolute or ../ link targets
- Keep Nomad clients patched — this is a security control
When it happens
Trigger: escapingfs.PathEscapesAllocDir returns escapes=true for hdr.Name or hdr.Linkname of a TypeSymlink entry — e.g. a link target like ../../outside or an absolute path.
Common situations: A task created symlinks pointing outside the alloc dir (shared host paths, /tmp links); adversarial or corrupted archives during cross-node migration; workloads using bind-mount-like relative links.
Related errors
- error evaluating symlink: %w
- artifact includes symlink that resolves outside of sandbox
- running container as ContainerAdmin is unsafe; change the co
- ACL token not found
- path escapes the alloc directory
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/62970f6a01dd8c1e.
Report an issue: GitHub.