VYPR
High severityNVD Advisory· Published Jul 23, 2024· Updated Aug 1, 2024

Nomad Vulnerable to Allocation Directory Path Escape Through Archive Unpacking

CVE-2024-6717

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.

PackageAffected versionsPatched versions
github.com/hashicorp/nomadGo
< 1.8.21.8.2

Affected products

4

Patches

1
ef6cdec8847e

security: add escape to arbitrary file access (#23319)

https://github.com/hashicorp/nomadDeniz Onur DuzgunJul 8, 2024via ghsa
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

News mentions

0

No linked articles in our index yet.