NousResearch/hermes-agent · error · ValueError

path is a sensitive credential file and cannot be attached

Error message

path is a sensitive credential file and cannot be attached

What it means

The attached file reference matches a sensitive credential file exactly (e.g. ~/.hermes/.env or a file in _SENSITIVE_HOME_FILES), so reference expansion refuses to inline its contents. This is the first, exact-match tier of _ensure_reference_path_allowed in agent/context_references.py, which protects credential material from being pulled into conversation context.

Source

Thrown at agent/context_references.py:495

        try:
            resolved.relative_to(allowed_root)
        except ValueError as exc:
            raise ValueError("path is outside the allowed workspace") from exc
    return resolved


def _ensure_reference_path_allowed(path: Path) -> None:
    from hermes_constants import get_hermes_home
    home = Path(os.path.expanduser("~")).resolve()
    hermes_home = get_hermes_home().resolve()

    blocked_exact = {home / rel for rel in _SENSITIVE_HOME_FILES}
    blocked_exact.add(hermes_home / ".env")
    blocked_dirs = [home / rel for rel in _SENSITIVE_HOME_DIRS]
    blocked_dirs.extend(hermes_home / rel for rel in _SENSITIVE_HERMES_DIRS)

    if path in blocked_exact:
        raise ValueError("path is a sensitive credential file and cannot be attached")

    for blocked_dir in blocked_dirs:
        try:
            path.relative_to(blocked_dir)
        except ValueError:
            continue
        raise ValueError("path is a sensitive credential or internal Hermes path and cannot be attached")

    # Anchor to the canonical read deny-list (agent/file_safety.get_read_block_error),
    # the single source of truth used by the file/terminal read path. The narrow
    # list above predates that guard and never caught the real credential stores:
    # provider keys (auth.json), Anthropic OAuth tokens (.anthropic_oauth.json),
    # MCP OAuth material (mcp-tokens/), webhook HMAC secrets, and project-local
    # .env files. That gap matters because the gateway feeds UNTRUSTED remote
    # message text into reference expansion, so `@file:~/.hermes/auth.json` from a
    # chat peer would otherwise read the operator's keys straight into context.
    # Routing through the canonical guard closes the gap today and keeps this path
    # protected automatically whenever that deny-list grows.

View on GitHub (pinned to c896c09c42)

Solutions

  1. Do not attach credential files; paste only the non-secret key NAMES you need help with.
  2. Create a sanitized copy (secrets redacted) inside the workspace and attach that instead.
  3. Reference documentation or an .env.example file rather than the live .env.

Example fix

# before
@file:~/.hermes/.env
# after — sanitized template inside the workspace
@file:./env.example
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

CREDENTIAL_NAMES = {'.env', '.env.local'}  # extend to match your policy

def is_credential_file(p: Path) -> bool:
    return p.name in CREDENTIAL_NAMES or p.suffix in {'.pem', '.key'}

Try / catch

try:
    attach(path)
except ValueError as e:
    if "sensitive credential file" in str(e):
        # never retry with the same path; offer a redacted copy instead
        ...

Prevention

When it happens

Trigger: A message with @file:~/.hermes/.env or @file: pointing at any of the exact sensitive home files (e.g. ~/.ssh/authorized_keys-style entries in _SENSITIVE_HOME_FILES). The resolved Path is compared by equality against blocked_exact.

Common situations: Trying to show the agent your configuration for debugging ('read my .env so you can fix the API key'); a remote gateway peer probing for credential files via @file: references.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/7a67c3a4a0105cc9. Report an issue: GitHub.