Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-5061 — Consul Template validated where a symlink pointed during template evaluation, but its later dependency fetch read the original path. Retargeting the link between those operations turned an in-sandbox file reference into an out-of-sandbox file disclosure. | Kitploit
Tools/GitHubGitHub/0xmrma/cve-2026-5061
Vulnerability AnalysisCode AnalysisExploitationData ExfiltrationLearning & Education
GitHub0xmrma/cve-2026-5061

CVE-2026-5061

Consul Template validated where a symlink pointed during template evaluation, but its later dependency fetch read the original path. Retargeting the link between those operations turned an in-sandbox file reference into an out-of-sandbox file disclosure.

View Repository
1132 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-5061

Consul Template validated where a symlink pointed during template evaluation, but its later dependency fetch read the original path. Retargeting the link between those operations turned an in-sandbox file reference into an out-of-sandbox file disclosure.

Intro

I found this issue while reviewing HashiCorp Consul Template, with a very specific security question in mind:

If sandbox_path validates a symlink during template evaluation, does the later file read stay bound to that same validated target?

In this case, the answer was no.

The file template helper resolved the path and enforced the configured sandbox during template evaluation. But after that check, it created a file dependency using the original raw path.

That dependency was fetched later.

If an attacker retargeted the symlink in the gap between validation and dependency fetch, Consul Template could read an out-of-sandbox file. If the link was restored before the next render, sandbox validation passed again and the cached external content was still rendered.

That issue became CVE-2026-5061.

HashiCorp bulletin: HCSEC-2026-12
IBM bulletin: CVE-2026-5061 security bulletin
CVE: CVE-2026-5061
Fixed in: 0.42.0

photo0


Attack Chain

attacker-controlled in-sandbox symlink -> sandbox validation resolves to safe target -> dependency stores original raw path -> attacker retargets link outside sandbox -> dependency fetch reads external file -> attacker restores safe link -> next validation passes -> cached external content is rendered


What Consul Template Does

Consul Template is a template rendering tool for Consul and Vault data.

It can run continuously, watch dependencies for changes, and render data into files or environment variables for applications to consume.

The file template helper reads a local file and inserts its contents into rendered output.

Because local file reads can expose process-readable secrets, Consul Template provides sandbox_path as a boundary for this helper.

The documented security property is straightforward:

  • paths passed to file must fall inside the configured sandbox
  • relative paths must not escape the sandbox
  • linked targets must not turn an allowed path into an external file read

That makes sandbox_path a real security boundary.

The important question was not whether the path looked like it was under the sandbox.

The real question was:

Does the file that gets read remain the same file that passed sandbox validation?

In vulnerable versions, it did not.


Why This Surface Was Worth Looking At

Filesystem sandboxes often fail at the gap between path validation and file access.

The common pattern is:

  • validate a path
  • release control back to the filesystem
  • use the path again later
  • assume it still identifies the same object

That assumption is unsafe when an attacker can modify a symlink or equivalent filesystem redirection between the two operations.

Consul Template made this surface especially interesting because template evaluation and dependency fetching were separate stages.

That separation created the right security question:

Is the dependency fetch bound to the validated target, or does it resolve the attacker-controlled path again?

That was the boundary I focused on.


Root Cause

The root cause was a time-of-check to time-of-use mismatch between:

  • sandbox validation in template/funcs.go
  • the later dependency read in dependency/file.go

At the tested revision, fileFunc() did this:

normalized := strings.TrimSpace(s)
err := pathInSandbox(sandboxPath, normalized)
if err != nil {
    return "", err
}

d, err := dep.NewFileQuery(s)

The validation helper correctly resolved symlinks before checking containment:

sandboxResolved, err := filepath.EvalSymlinks(filepath.Clean(sandbox))
targetResolved, err := filepath.EvalSymlinks(filepath.Clean(path))

rel, err := filepath.Rel(sandboxResolved, targetResolved)
if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
    return fmt.Errorf("'%s' is outside of sandbox", path)
}

So the sandbox check itself understood the resolved target.

But that resolved target was discarded.

NewFileQuery() stored the original string instead:

return &FileQuery{
    stopCh: make(chan struct{}, 1),
    path:   s,
}, nil

Then the later dependency fetch read that path again:

data, err := os.ReadFile(d.path)

That is the whole vulnerability.

The code checked one filesystem resolution, then later used another.

Why this is exploitable

Because a symlink is mutable.

The attacker does not need to make an out-of-sandbox target pass pathInSandbox() directly.

They only need to change what the already-approved raw path resolves to after validation but before Fetch() performs the read.

The sequence is:

  • the link resolves to a safe file during pathInSandbox()
  • validation succeeds
  • FileQuery records the raw link path
  • the link is replaced or retargeted to an external file
  • os.ReadFile(d.path) resolves the link again
  • the outside file is read
  • the fetched value is cached in the template brain
  • the link is restored before the next template evaluation
  • validation succeeds again
  • cached external content is returned and rendered

That last step is important.

Restoring the safe link did not remove the already-fetched secret from the dependency cache.


What Makes This a Security Issue, Not Just a Filesystem Race

The important distinction is bypass of an explicit security control.

This was not merely:

"the file changed while Consul Template was watching it"

Watching files for changes is expected behavior.

The real issue was:

a path that passed the documented sandbox restriction could later be used to read a file outside that sandbox

That is a direct trust-boundary failure.

The application had already made a security decision:

  • this target is inside the sandbox
  • therefore it is safe to register and fetch

But the later fetch was not tied to the target that justified that decision.

That is what turned ordinary filesystem mutability into a vulnerability.


Proof of Concept

I built a standalone reproducer around the exact evaluation and dependency-fetch sequence.

The controlled setup used:

  • a configured sandbox directory
  • a safe file inside that sandbox
  • a secret file outside the sandbox
  • a watched symlink path inside the sandbox
  • deterministic link swaps around the dependency fetch

The reproduction flow was:

  1. Point the watched symlink at the safe in-sandbox file.
  2. Evaluate the file helper so sandbox validation succeeds and the raw path is registered as a dependency.
  3. Retarget the watched symlink to the outside secret before dependency fetch.
  4. Run the dependency fetch and allow os.ReadFile(d.path) to read through the redirected link.
  5. Store the fetched value in the template cache.
  6. Restore the symlink to the safe in-sandbox file.
  7. Evaluate the template again.
  8. Confirm sandbox validation still succeeds.
  9. Confirm the rendered output contains the previously fetched outside secret.

The observed behavior was:

  • initial sandbox validation passed
  • the dependency retained the original link path
  • the fetch read the out-of-sandbox file after the link changed
  • the safe target was restored before the next render
  • the next sandbox check passed
  • the rendered output matched the external secret exactly by SHA-256

That hash comparison mattered.

Download Tool