hashicorp/nomad · error

destination escapes allocation directory

Error message

destination escapes allocation directory

What it means

DispatchPayloadConfig.Validate() rejects a `template` dispatch payload whose destination `File` resolves outside the allocation directory. It calls escapingfs.PathEscapesAllocViaRelative("task/local/", d.File), and if the path escapes (e.g. via `..` traversal or symlinks), validation fails. This guards the `task/local/` sandbox against path traversal.

Source

Thrown at nomad/structs/structs.go:6151

	File string
}

func (d *DispatchPayloadConfig) Copy() *DispatchPayloadConfig {
	if d == nil {
		return nil
	}
	nd := new(DispatchPayloadConfig)
	*nd = *d
	return nd
}

func (d *DispatchPayloadConfig) Validate() error {
	// Verify the destination doesn't escape
	escaped, err := escapingfs.PathEscapesAllocViaRelative("task/local/", d.File)
	if err != nil {
		return fmt.Errorf("invalid destination path: %v", err)
	} else if escaped {
		return fmt.Errorf("destination escapes allocation directory")
	}

	return nil
}

const (
	TaskLifecycleHookPrestart  = "prestart"
	TaskLifecycleHookPoststart = "poststart"
	TaskLifecycleHookPoststop  = "poststop"
)

type TaskLifecycleConfig struct {
	Hook    string
	Sidecar bool
}

func (d *TaskLifecycleConfig) Copy() *TaskLifecycleConfig {
	if d == nil {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set the template `destination` to a relative path inside the alloc dir, e.g. `task/local/payload.txt` or `local/payload.txt`.
  2. Remove any `../` traversal segments from the destination path.
  3. If you need data in another location, copy it at runtime from task/local/ rather than pointing the destination there.

Example fix

// before
template {
  data        = "{{ payload }}"
  destination = "../../shared/input.txt"
}
// after
template {
  data        = "{{ payload }}"
  destination = "task/local/input.txt"
}
Defensive patterns

Strategy: validation

Validate before calling

func validDispatchDestination(dest string) bool {
	if filepath.IsAbs(dest) {
		return false
	}
	escaped, err := escapingfs.PathEscapesAllocViaRelative("task/local/", dest)
	return err == nil && !escaped
}
// call before building the job: validDispatchDestination(cfg.File)

Prevention

When it happens

Trigger: Submitting or validating a job whose `template` block uses `data` (dispatch payload) with a `destination` file path such as `../../etc/foo`, an absolute path, or any relative path that escapes `task/local/`.

Common situations: Typo of extra `../` segments in a template destination; copy-pasting paths from other tools assuming a different working directory; trying to write outside the alloc dir to share files between tasks; absolute paths (`/etc/...`) used by mistake.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/12c93d6464f3e952. Report an issue: GitHub.