Nomad Vulnerable to Allocation Directory Path Escape Through Archive Unpacking
Description
HashiCorp Nomad and Nomad Enterprise 1.6.12 up to 1.7.9, and 1.8.1 archive unpacking during migration is vulnerable to path escaping of the allocation directory. This vulnerability, CVE-2024-6717, is fixed in Nomad 1.6.13, 1.7.10, and 1.8.2.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
HashiCorp Nomad up to versions 1.6.12-1.7.9 and 1.8.1 has a path traversal vulnerability in archive unpacking during allocation migration, allowing files to escape the allocation directory.
Vulnerability
Details
A path escaping vulnerability exists in HashiCorp Nomad (including Nomad Enterprise) versions 1.6.12 through 1.7.9 and 1.8.1. The issue occurs during the unpacking of archived artifacts (such as zip, tgz, bz2, xz) when performing allocation migration. The allocation working directory is intended to contain task directories, logs, and downloaded artifacts, but the unpacking process does not properly validate that archive entries remain within the intended allocation directory [1][4].
Exploitation and
Attack Surface
An attacker with the ability to craft a malicious archive and have it fetched as an artifact by a Nomad client can exploit this vulnerability. The archive can contain relative path entries (e.g., using ../) that escape the allocation directory. This can be achieved by a compromised peer client sending a malicious archive during migration, as the vulnerability specifically affects the stream allocation directories [2][4]. No authentication is required beyond the ability to submit a job or influence artifact fetching.
Impact
Successful exploitation allows an attacker to write files to arbitrary locations on the Nomad client filesystem outside the intended allocation directory. This could lead to overwriting critical system files, configuration files, or binaries, potentially resulting in privilege escalation, denial of service, or lateral movement within the cluster [1][4].
Mitigation
HashiCorp has released fixed versions: Nomad 1.6.13, 1.7.10, and 1.8.2. These releases add a check for relative paths escaping the allocation directory when unpacking archives during migration, hardening clients against malicious archives [2]. Users are advised to upgrade to the latest patched versions as soon as possible; no workarounds are mentioned in the advisories [4].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/hashicorp/nomadGo | < 1.8.2 | 1.8.2 |
Affected products
4- ghsa-coords2 versionspkg:golang/github.com/hashicorp/nomadpkg:rpm/opensuse/govulncheck-vulndb&distro=openSUSE%20Leap%2015.6
< 1.8.2+ 1 more
- (no CPE)range: < 1.8.2
- (no CPE)range: < 0.0.20260114T191543-150000.1.137.1
- HashiCorp/Nomadv5Range: 0
- HashiCorp/Nomad Enterprisev5Range: 0
Patches
1ef6cdec8847esecurity: add escape to arbitrary file access (#23319)
4 files changed · +72 −6
.changelog/23319.txt+3 −0 added@@ -0,0 +1,3 @@ +```release-note:security +migration: Added a check for relative paths escaping the allocation directory when unpacking archive during migration, to harden clients against compromised peer clients sending malicious archives +```
client/allocwatcher/alloc_watcher.go+12 −6 modified@@ -587,6 +587,12 @@ func (p *remotePrevAlloc) streamAllocDir(ctx context.Context, resp io.ReadCloser p.prevAllocID, p.allocID, err) } + if escapes, err := escapingfs.PathEscapesAllocDir(dest, "", hdr.Name); err != nil { + return fmt.Errorf("error evaluating object: %w", err) + } else if escapes { + return fmt.Errorf("archive contains object that escapes alloc dir") + } + if hdr.Name == errorFilename { // Error snapshotting on the remote side, try to read // the message out of the file and return it. @@ -618,12 +624,12 @@ func (p *remotePrevAlloc) streamAllocDir(ctx context.Context, resp io.ReadCloser return fmt.Errorf("error creating symlink: %w", err) } - escapes, err := escapingfs.PathEscapesAllocDir(dest, "", hdr.Name) - if err != nil { - return fmt.Errorf("error evaluating symlink: %w", err) - } - if escapes { - return fmt.Errorf("archive contains symlink that escapes alloc dir") + 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
client/allocwatcher/alloc_watcher_test.go+36 −0 modified@@ -23,6 +23,7 @@ import ( "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/testutil" + "github.com/shoenig/test/must" "github.com/stretchr/testify/require" ) @@ -276,3 +277,38 @@ func TestPrevAlloc_StreamAllocDir_Error(t *testing.T) { t.Fatalf("expected foo.txt to be size 1 but found %d", fi.Size()) } } + +// TestPrevAlloc_StreamAllocDir_FileEscape asserts that an error is returned +// when the tar archive contains a file that escapes the allocation directory. +func TestPrevAlloc_StreamAllocDir_FileEscape(t *testing.T) { + ci.Parallel(t) + + // This test only unit tests streamAllocDir so we only need a partially + // complete remotePrevAlloc + prevAlloc := &remotePrevAlloc{ + logger: testlog.HCLogger(t), + allocID: "123", + prevAllocID: "abc", + migrate: true, + } + + // Create a tar archive with a file that escapes the allocation directory + tarBuf := bytes.NewBuffer(nil) + tw := tar.NewWriter(tarBuf) + err := tw.WriteHeader(&tar.Header{ + Name: "../escape.txt", + Mode: 0666, + Size: 1, + ModTime: time.Now(), + Typeflag: tar.TypeReg, + }) + must.NoError(t, err) + _, err = tw.Write([]byte{'a'}) + t.Cleanup(func() { tw.Close() }) + must.NoError(t, err) + + // Attempt to stream the allocation directory + dest := t.TempDir() + err = prevAlloc.streamAllocDir(context.Background(), io.NopCloser(tarBuf), dest) + must.EqError(t, err, "archive contains object that escapes alloc dir") +}
client/allocwatcher/alloc_watcher_unix_test.go+21 −0 modified@@ -115,6 +115,27 @@ func TestPrevAlloc_StreamAllocDir_BadSymlink(t *testing.T) { must.EqError(t, err, "archive contains symlink that escapes alloc dir") } +func TestPrevAlloc_StreamAllocDir_BadSymlink_Linkname(t *testing.T) { + ci.Parallel(t) + + // Create a tar archive with a symlink that attempts to escape the allocation directory + var buf bytes.Buffer + tw := tar.NewWriter(&buf) + t.Cleanup(func() { tw.Close() }) + must.NoError(t, tw.WriteHeader(&tar.Header{ + Typeflag: tar.TypeSymlink, + Name: "symlink", + Linkname: "../escape_attempt", + Mode: 0600, + })) + + newDir := t.TempDir() + prevAlloc := &remotePrevAlloc{logger: testlog.HCLogger(t)} + err := prevAlloc.streamAllocDir(context.Background(), io.NopCloser(&buf), newDir) + + must.EqError(t, err, "archive contains symlink that escapes alloc dir") +} + func testTar(dir string) (*bytes.Buffer, error) { buf := new(bytes.Buffer)
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-5mqx-rpxv-mvxjghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-6717ghsaADVISORY
- discuss.hashicorp.com/t/hcsec-2024-15-nomad-vulnerable-to-allocation-directory-path-escape-through-archive-unpacking/68781ghsaWEB
- github.com/hashicorp/nomad/commit/ef6cdec8847e0698d386d1fd3761743df758ef99ghsaWEB
- github.com/hashicorp/nomad/releases/tag/v1.8.2ghsaWEB
News mentions
0No linked articles in our index yet.