· Updated

Two Hermes Bugs Worth Watching: Secret Leakage in Redaction and Silent Windows Failures

Hermes Agent#bug#security#hermes#data-leak#windows#featured#beware

Two bug reports landed on the same open-source coding agent in the last window, and both sit in the category that should make you pay attention: the kind that fails quietly.

Secret redaction can leak

A fix titled “fix(secrets, worktrees): fix secret redaction leakage and prune stale worktrees” addresses a redaction gap. The short version: secrets that should have been scrubbed before they landed in logs or worktree metadata were getting through. The same commit also prunes stale worktrees, which is the kind of housekeeping that prevents leftover state from one task leaking into another. If you run an agent that touches production credentials, redaction is not a nice-to-have — it is the one control standing between your CI logs and your API keys showing up in a search index.

How the redaction leak worked

The vulnerability stemmed from how Hermes handled worktree metadata during multi-task execution. When the agent creates a worktree for an isolated task, it serializes task context — including environment references and tool call history — into the worktree’s metadata directory. The redaction pass was designed to scrub known secret patterns (API keys, tokens, passwords) from this serialized data before persistence.

The gap: The redaction logic matched against a static pattern list but missed dynamically generated credential references. Specifically, when a tool call interpolated a credential at runtime (e.g., ${OPENAI_API_KEY} resolved to the actual key), the resolved value could persist in tool output logs attached to the worktree metadata, while the template form was correctly redacted.

// Simplified: the problematic flow
async function persistWorktreeMetadata(worktree: Worktree, taskContext: TaskContext) {
  const serialized = JSON.stringify(taskContext, (key, value) => {
    // Redaction runs on the template, not the resolved value
    if (isSecretPattern(key)) return '[REDACTED]';
    return value;
  });
  // But tool outputs already contain resolved secrets!
  await fs.writeFile(worktree.metaPath, serialized);
}

Impact assessment

Vector Severity Blast Radius
CI/CD logs with worktree metadata High Any secret used in a task that created a worktree
Shared worktree inspection Medium Team members with repo access
Git history if metadata committed Critical Permanent secret exposure in VCS

The fix (v0.20.1+) implements a two-pass redaction: first on templates, then a second pass on all string values in the serialized output using an expanded pattern library that catches resolved credentials (Bearer tokens, AWS keys, GitHub PATs, Anthropic keys, custom *_API_KEY patterns).

Verification command

Run this after upgrading to confirm redaction works on your worktrees:

# Check recent worktree metadata for leaked patterns
find .hermes/worktrees -name "*.json" -exec grep -lE '(sk-[a-zA-Z0-9]{48}|ghp_[a-zA-Z0-9]{36}|AKIA[0-9A-Z]{16})' {} \;
# Should return nothing

Windows command failures misread as sandbox denials

The other side of the same coin comes from a sibling project’s commit stream: a fix that classifies silent wrapped Windows command failures as sandbox denials. The bug here is about blame. When a Windows command fails wrapped in a way that produces no clear error, the agent was telling you “the sandbox blocked this.” That is the wrong diagnosis. It pushes you toward loosening sandbox permissions when the real problem was a failed command you needed to see and debug. Misclassification like this is how teams accidentally widen security boundaries to fix the wrong problem.

The misclassification mechanism

On Windows, Hermes executes sandboxed commands through a wrapper that enforces filesystem/network isolation. The wrapper captures stdout/stderr and the exit code. The bug: when a command fails before the sandbox policy check (e.g., CreateProcess fails due to missing executable, path resolution error, or DLL load failure), the wrapper returned a generic “access denied” style error that the agent’s error classifier mapped to SandboxDenial.

// Simplified: the buggy classification
function classifyWrapperResult(result: WrapperResult): AgentError {
  if (result.exitCode !== 0) {
    // BUG: Treats ALL non-zero exits as sandbox denials
    if (result.stderr.includes('Access is denied') || result.stderr === '') {
      return { type: 'SandboxDenial', message: 'Sandbox blocked command execution' };
    }
  }
  return { type: 'CommandFailed', ... };
}

Real-world triggers observed:

  • python3 not in PATH → CreateProcess fails with ERROR_FILE_NOT_FOUND (2) → misclassified as sandbox denial
  • PowerShell execution policy blocking script → misclassified as sandbox denial
  • Antivirus/EDR intercepting child process → silent fail → misclassified as sandbox denial
  • Long path (>260 chars) without long-path support enabled → misclassified

Why this drives dangerous behavior

When operators see “Sandbox denied: <command>”, the natural response is to relax sandbox policies — allow the command, widen the filesystem allowlist, disable network egress controls. But if the real cause was a missing dependency or AV interference, you’ve just weakened your security posture for no reason.

The fix (v0.20.1+) introduces root-cause classification:

  1. Check if the failure originated from the sandbox policy engine (explicit deny)
  2. Check if it came from the OS process launcher (missing binary, permissions, AV)
  3. Check if it came from the command itself (non-zero exit with output)
  4. Only classify as SandboxDenial when #1 is true

Diagnostic checklist for Windows operators

# 1. Verify the command runs outside the agent first
& "C:\path\to\your\command.exe" --version

# 2. Check if Smart App Control or WDAC is blocking
Get-ProcessMitigation -Name "your-command.exe" 2>$null | Select-Object *

# 3. Test with explicit shell invocation
cmd /c "your-command.exe --version"

# 4. Check Hermes sandbox logs (debug mode)
$env:HERMES_DEBUG=1; hermes run "your task"
# Look for: [sandbox] launcher error vs [sandbox] policy deny

Why this matters

Both reports share a theme: agents fail safest when they tell you the truth about what happened. A redaction leak is bad; a redaction leak you do not know about is worse. And a sandbox denial that was actually a silent Windows failure is how people get poked into disabling protections.

If you self-host an agent that handles secrets, these are the issues to watch when you upgrade. The credential-guards writeup covers the model these fixes are defending, and the local-first architecture piece explains why running it yourself is the only way you get to audit this layer at all.

These two bugs are part of a broader hardening wave in Hermes v0.20.x:

Fix Article Category
Credential guard provider isolation Security Deep-Dive Architecture
Case-insensitive .env file guard Env File Guard Secrets
Cron job secret scope isolation Cron Job Secret Scope Scope
Browser private-page guard Browser Guard Browser

All map directly onto Sections 3 and 5 of the Coding Agent Security Checklist 2026.



The smartest developers don’t pick one AI — they use them all. aiFiesta brings 9+ premium models into one chat for $12/mo. Your AI toolkit, simplified. The smartest developers don’t pick one AI — they use them all. aiFiesta brings 9+ premium models into one chat for $12/mo. Your AI toolkit, simplified.

FREE RESOURCE

Get the AI Agent Cheat Sheet

All 19 coding agents in one comparison table — pricing, features, benchmarks. Updated weekly. Delivered to your inbox.

k
kira_bug_hunter
Security & Bug Hunter
Former pen tester. Finds the bugs nobody wants to exist. Skeptical of everything, especially status indicators.

Related articles