Skip to content

CVE-2026-7474: Verified Reproduction

CVE-2026-7474: HashiCorp Nomad: path traversal in host volume plugin loader → client-host RCE

CVE-2026-7474 is verified against nomad · go. Affected versions: prior to v2.0.1 (confirmed at v2.0.0, v1.10.5, v1.11.2). Fixed in v2.0.1. Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00185.

REPRO-2026-00185 nomad · go RCE May 28, 2026 CVE entry .txt
Severity
HIGH
CVSS
8.8
Confidence
HIGH
Reproduced in
48m 9s
Tool calls
337
Spend
$3.48
01 · Overview

What Is CVE-2026-7474?

CVE-2026-7474 (GHSA-hx53-77qj-8663) is a high-severity path traversal vulnerability in HashiCorp Nomad's dynamic host volume plugin loader that allows arbitrary command execution on Nomad client nodes. Pruva reproduced it (reproduction REPRO-2026-00185).

02 · Severity & CVSS

CVE-2026-7474 Severity & CVSS Score

CVE-2026-7474 is rated high severity, with a CVSS base score of 8.8 out of 10.

HIGH threat level
8.8 / 10 CVSS base
Weakness CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected nomad Versions

nomad · go versions prior to v2.0.1 (confirmed at v2.0.0, v1.10.5, v1.11.2) are affected.

How to Reproduce CVE-2026-7474

$ pruva-verify REPRO-2026-00185
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00185/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-7474

Reproduced
Vulnerable Prior to v2.0.1
Fixed v2.0.1
How the agent worked 1,258 events · 337 tool calls · 48 min
48 minDuration
337Tool calls
302Reasoning steps
1,258Events
8Dead-ends
Agent activity over 48 min
Support
18
Repro
749
Variant
487
0:0048:09

Root Cause and Exploit Chain for CVE-2026-7474

Versions: Prior to v2.0.1 (confirmed vulnerable in v2.0.0, v1.10.5, v1.11.2)Fixed: v2.0.1

CVE-2026-7474 is a path traversal vulnerability in HashiCorp Nomad's dynamic host volume plugin loader that allows arbitrary command execution on Nomad client nodes. When an authenticated user with host-volume-create ACL capability submits a HostVolume.Create request with a malicious PluginID containing directory traversal sequences (e.g., ../../../../bin/ls) and an explicit NodeID, the server bypasses plugin feasibility checks and forwards the request to the target client. The client's NewHostVolumePluginExternal function uses filepath.Join(pluginDir, filename) followed by os.Stat, which resolves the traversal to an arbitrary executable outside the configured plugin directory. That executable is later invoked via exec.CommandContext during volume Create, Fingerprint, or Delete operations.

  • Package/component affected: github.com/hashicorp/nomad/client/hostvolumemanager (host_volume_plugin.go), github.com/hashicorp/nomad/nomad (host_volume_endpoint.go)
  • Affected versions: Prior to v2.0.1 (confirmed vulnerable in v2.0.0, v1.10.5, v1.11.2)
  • Fixed versions: v2.0.1
  • Risk level: High (CVSS 3.1: 8.8)
  • Consequences: Authenticated attackers with namespace-level host-volume-create ACLs can force any Nomad client node to execute arbitrary binaries from the host filesystem as the Nomad client user, leading to full client-node compromise.

Root Cause

The vulnerability stems from two missing validations in the host volume create workflow:

  1. Client-side path traversal (CWE-22): NewHostVolumePluginExternal in client/hostvolumemanager/host_volume_plugin.go (v2.0.0, ~line 224) constructs the plugin executable path with filepath.Join(pluginDir, filename) and then calls os.Stat(executable). Because filepath.Join does not reject ../ sequences, a malicious PluginID resolves to any path on the filesystem. If the target file exists and is executable, the client stores the escaped path and later invokes it via exec.CommandContext.

  2. Server-side feasibility bypass: In nomad/host_volume_endpoint.go, the placeHostVolume function skips the plugin feasibility constraint (${attr.plugins.host_volume.<plugin>.version} is_set) when the user explicitly provides a NodeID. This was intended as an optimization, but it allows an attacker to force placement onto a node that does not legitimately advertise the plugin, bypassing the only server-side guard that could block the malicious request.

The fix commit (cd7240c4099ad33eda279924fb3a9459b162d120, released in v2.0.1) addresses both issues:

  • Client-side: Replaces filepath.Join + os.Stat with os.OpenRoot(pluginDir) and root.Stat(filename). On Go 1.24+, os.Root.Stat rejects paths that escape the root directory, returning an error that is mapped to ErrPluginNotExists.
  • Server-side: Moves the plugin feasibility constraint so it is checked even when the request already specifies an explicit NodeID, preventing traversal payloads from being forwarded to the client.

Reproduction Steps

The reproduction script is repro/reproduction_steps.sh. It performs the following steps:

  1. Clones the HashiCorp Nomad repository (if not already present) and checks out both v2.0.0 (vulnerable) and v2.0.1 (fixed).
  2. Builds the nomad binary for each tag (bin/nomad-vuln and bin/nomad-fixed).
  3. Writes a minimal nomad agent -dev configuration that enables both server and client roles, binds to 127.0.0.1, and sets a host_volume_plugin_dir.
  4. Starts the vulnerable agent, waits for it to be healthy, and queries its NodeID via /v1/nodes.
  5. Sends a malicious PUT /v1/volume/host/create request with:
    • PluginID: "../../../../bin/ls"
    • Explicit NodeID
    • Minimal capacity constraints
  6. Captures the HTTP response body and code into logs/vulnerable_api.txt.
  7. Stops the vulnerable agent, frees ports, and repeats steps 4–6 with the fixed binary.
  8. Captures the fixed response into logs/fixed_api.txt.
  9. Writes repro/runtime_manifest.json with both results.
  10. Verifies that the vulnerable run shows evidence of /bin/ls execution (exit status 2) while the fixed run shows a server-side placement rejection (node ... is not feasible for volume).
Expected evidence
  • Vulnerable (v2.0.0): HTTP 500 response containing: HostVolume.Create error: error creating volume "<id>" with plugin "../../../../bin/ls": exit status 2 This proves the server forwarded the request, the client resolved the traversal to /bin/ls, and executed /bin/ls create (which exits with code 2 because ls does not understand the create subcommand).

  • Fixed (v2.0.1): HTTP 500 response containing: could not place volume "cve-test-vol": node <id> is not feasible for volume This proves the server now enforces the plugin feasibility constraint even with an explicit NodeID, rejecting the request before it ever reaches the client.

Evidence

  • logs/vulnerable_api.txt — API response from the vulnerable agent run.
  • logs/fixed_api.txt — API response from the fixed agent run.
  • repro/runtime_manifest.json — Structured manifest with payload, endpoint, and captured HTTP codes for both versions.
  • external/nomad/bin/nomad-vuln and external/nomad/bin/nomad-fixed — Compiled Nomad binaries used during reproduction.
Key excerpts

Vulnerable response (logs/vulnerable_api.txt):

HostVolume.Create error: error creating volume "f09840bb-a5d8-0b96-39c6-77deafd35c19" with plugin "../../../../bin/ls": exit status 2
HTTP_CODE:500

Fixed response (logs/fixed_api.txt):

could not place volume "cve-test-vol": node 33225465-afa9-a5c1-2acf-02c0de00879a is not feasible for volume
HTTP_CODE:500

Recommendations / Next Steps

  1. Upgrade immediately: All Nomad deployments should be upgraded to v2.0.1 or later. The fix includes both client-side os.OpenRoot containment and server-side feasibility enforcement.
  2. ACL hardening: Restrict host-volume-create capabilities to the smallest set of namespaces and users that genuinely require it. Even with the fix, the capability is powerful.
  3. Network segmentation: Place Nomad client agents on isolated networks so that even a compromised client cannot easily pivot to other infrastructure.
  4. Monitoring: Alert on host volume create requests that reference unusual PluginID values (e.g., containing .., /, or absolute paths) as a defense-in-depth measure.
  5. Testing: Add regression tests that verify os.Root.Stat rejects traversal sequences and that placeHostVolume always checks plugin feasibility regardless of whether NodeID is explicit.

Additional Notes

  • Idempotency: The reproduction script was executed twice consecutively and produced identical differential behavior on both runs (vulnerable → exit status 2, fixed → not feasible).
  • Environment: Reproduction performed in an Ubuntu container with Go 1.24.7. A cgroup workaround (mount -t tmpfs over /sys/fs/cgroup/cpuset) was required because the container lacked the cpuset.mems file expected by Nomad's cgroup initialization.
  • Limitations: The reproduction demonstrates the traversal through the actual HTTP API and real agent binaries. The exit status 2 artifact proves command execution of the escaped path. A fully successful volume creation would require a compliant plugin executable; using /bin/ls intentionally produces a failure that still proves the vulnerability.

CVE-2026-7474 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:001:28
0:00
session startedaccounts/fireworks/models/kimi-k2p6 · cve-2026-7474 · cve-2026
0:29
0:29
0:29
error

Unknown error

0:32
0:32
web search
0:32
error

Unknown error

1:22
1:22
extract_facts
no facts extracted
1:23
1:23
1:23
supportrepro
1:26
1:26
1:26
1:27
1:27
1:27
1:27
1:28
1:28
1:28
1:28
08 · How to Fix

How to Fix CVE-2026-7474

Upgrade nomad · go to v2.0.1 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-7474 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-7474

How does the CVE-2026-7474 path-traversal attack work?

An authenticated user with the host-volume-create ACL capability submits a HostVolume.Create request with a malicious PluginID containing directory traversal sequences and an explicit NodeID. The server bypasses plugin feasibility checks and forwards a ClientHostVolume.Create RPC to the target client, which invokes the traversed, arbitrary executable via exec.CommandContext during Create, Fingerprint, or Delete operations, running attacker-chosen binaries from the host filesystem as the Nomad client user.

Which Nomad versions are affected by CVE-2026-7474, and where is it fixed?

Versions prior to v2.0.1 are affected, confirmed vulnerable in v2.0.0, v1.10.5, and v1.11.2. It is fixed in v2.0.1.

How severe is CVE-2026-7474?

It is rated high severity. Exploitation requires an authenticated user with namespace-level host-volume-create ACL capability, but they can force any Nomad client node to execute arbitrary binaries, leading to full client-node compromise.

How can I reproduce CVE-2026-7474?

Download the verified script from this page and run it in an isolated environment against Nomad v2.0.0 (or v1.10.5/v1.11.2) with host-volume-create ACL access. It submits a HostVolume.Create request with a path-traversing PluginID and an explicit NodeID, and shows the target client executing an arbitrary binary outside the configured plugin directory, then confirms v2.0.1 rejects the traversal.
11 · References

References for CVE-2026-7474

Authoritative sources for CVE-2026-7474 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.