hermes - ✅(Solved) Fix Security: read_file can exfiltrate credentials from auth.json and .anthropic_oauth.json [1 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#17656Fetched 2026-04-30 06:46:11
View on GitHub
Comments
2
Participants
2
Timeline
8
Reactions
0
Author
Participants
Timeline (top)
labeled ×5commented ×2cross-referenced ×1

The agent's read_file tool is sandboxed to HERMES_HOME (typically ~/.hermes or /opt/data in containerized deploys). Inside that scope, agent/file_safety.py:get_read_block_error deny-lists skills/.hub/ but nothing else. That leaves credential-pool files — auth.json (provider OAuth state + plaintext API keys) and .anthropic_oauth.json (Anthropic PKCE tokens) — fully readable by the agent. A prompt-injection attack reaching read_file can exfiltrate active provider credentials in plaintext.

Error Message

Extend get_read_block_error to also block reads of ${HERMES_HOME}/auth.json, ${HERMES_HOME}/auth.lock, and ${HERMES_HOME}/.anthropic_oauth.json. Same pattern as the existing skills/.hub/ deny — pure path check, no I/O. Returns a "credential store, cannot be read directly" error message so the agent (and humans reading the trace) understand the boundary.

Root Cause

The agent's read_file tool is sandboxed to HERMES_HOME (typically ~/.hermes or /opt/data in containerized deploys). Inside that scope, agent/file_safety.py:get_read_block_error deny-lists skills/.hub/ but nothing else. That leaves credential-pool files — auth.json (provider OAuth state + plaintext API keys) and .anthropic_oauth.json (Anthropic PKCE tokens) — fully readable by the agent. A prompt-injection attack reaching read_file can exfiltrate active provider credentials in plaintext.

Fix Action

Fix / Workaround

We're running this fix as a local Dockerfile-overlay patch in production. Happy to send it as a PR if useful — it's:

  • ~30 lines added to agent/file_safety.py (one helper + one extra branch in get_read_block_error).
  • 7 unit tests covering the deny-list, the existing skills/.hub regression, path-traversal resolution, and the negative case (arbitrary HERMES_HOME files remain readable). All pass against main with the patch applied.

PR fix notes

PR #17659: fix(file-safety): block read_file on HERMES_HOME credential stores (#17656)

Description (problem / solution / changelog)

Summary

  • Extend agent/file_safety.py::get_read_block_error to deny reads of ${HERMES_HOME}/auth.json, ${HERMES_HOME}/auth.lock, and ${HERMES_HOME}/.anthropic_oauth.json.
  • Adds 8 unit tests covering the deny list, the existing skills/.hub regression, path traversal, symlink indirection, and the negative case (arbitrary HERMES_HOME files remain readable).

The bug

read_file is sandboxed to HERMES_HOME, but inside that scope get_read_block_error only denies skills/.hub/. That leaves the credential-pool files fully readable by the agent:

>>> from agent.file_safety import get_read_block_error
>>> get_read_block_error(\"/opt/data/auth.json\")
>>> # Returns None — read is allowed.

auth.json materializes at \${HERMES_HOME}/auth.json mode 0600 with the active key as plaintext in credential_pool.<provider>[].access_token. Mode 0600 prevents other Unix users from reading the file, but the agent runs as the file's owner — read_file is unaffected. A prompt-injection attack reaching read_file can exfiltrate active provider credentials in plaintext.

The fix

Extend get_read_block_error with a second deny set covering the three credential paths identified in #17656:

  • \${HERMES_HOME}/auth.json — provider OAuth state + plaintext API keys
  • \${HERMES_HOME}/auth.lock — auth-store lock companion
  • \${HERMES_HOME}/.anthropic_oauth.json — Anthropic PKCE tokens

The check uses the same Path.resolve() pattern as the existing skills/.hub block, so symlink shims and path traversal are caught too. The denial message points at the boundary so the agent (and humans reading the trace) understand why the read failed.

The agent doesn't need to read these directly — auxiliary_client and credential_pool consume them through process env / OAuth flows that bypass read_file.

Test plan

  • Focused tests pass: tests/agent/test_file_safety_credentials.py (8 tests).
  • Regression guard: on clean origin/main, the 5 tests that assert credential-file blocking fail; with the patch they pass. The 3 negative/regression tests (skills/.hub still blocked, arbitrary files stay readable, subdirectory auth.json not over-blocked) pass on both branches.
  • Adjacent suite: tests/tools/test_file_read_guards.py and tests/agent/test_copilot_acp_client.py show the same 7 baseline failures on clean origin/main and on this branch (HERMES_WRITE_SAFE_ROOT-related write-path tests, unrelated to this change).

Related

  • Fixes #17656.
  • Complementary to (not duplicate of) #16851, which adds read-side denial for home-directory credentials (~/.ssh, ~/.aws, ~/.config/gh, etc.). #16851 does not cover HERMES_HOME credential files; this PR closes that gap.

Changed files

  • agent/file_safety.py (modified, +34/-1)
  • tests/agent/test_file_safety_credentials.py (added, +149/-0)
  • tools/file_tools.py (modified, +7/-2)

Code Example

>>> from agent.file_safety import get_read_block_error
>>> get_read_block_error("/opt/data/auth.json")
>>> # Returns None — read is allowed.
RAW_BUFFERClick to expand / collapse

Summary

The agent's read_file tool is sandboxed to HERMES_HOME (typically ~/.hermes or /opt/data in containerized deploys). Inside that scope, agent/file_safety.py:get_read_block_error deny-lists skills/.hub/ but nothing else. That leaves credential-pool files — auth.json (provider OAuth state + plaintext API keys) and .anthropic_oauth.json (Anthropic PKCE tokens) — fully readable by the agent. A prompt-injection attack reaching read_file can exfiltrate active provider credentials in plaintext.

Reproducer

Tested against the current main branch (commit e63929d4).

>>> from agent.file_safety import get_read_block_error
>>> get_read_block_error("/opt/data/auth.json")
>>> # Returns None — read is allowed.

Concretely on a running deployment with DEEPSEEK_API_KEY set in process env: auth.json materializes at ${HERMES_HOME}/auth.json mode 0600 with the active key as plaintext in the credential_pool.deepseek[].access_token field. Mode 0600 prevents other Unix users from reading the file, but the agent itself runs as the file's owner — read_file is unaffected.

Suggested fix

Extend get_read_block_error to also block reads of ${HERMES_HOME}/auth.json, ${HERMES_HOME}/auth.lock, and ${HERMES_HOME}/.anthropic_oauth.json. Same pattern as the existing skills/.hub/ deny — pure path check, no I/O. Returns a "credential store, cannot be read directly" error message so the agent (and humans reading the trace) understand the boundary.

The agent doesn't need to read its own credentials — provider tools (auxiliary_client, credential_pool) consume them through process env / OAuth flows that bypass read_file.

Materials we have ready

We're running this fix as a local Dockerfile-overlay patch in production. Happy to send it as a PR if useful — it's:

  • ~30 lines added to agent/file_safety.py (one helper + one extra branch in get_read_block_error).
  • 7 unit tests covering the deny-list, the existing skills/.hub regression, path-traversal resolution, and the negative case (arbitrary HERMES_HOME files remain readable). All pass against main with the patch applied.

Let me know if you'd like the PR or if you'd prefer a different shape (e.g. extending tools/credential_files.py to centrally register these paths so other readers benefit too).

extent analysis

TL;DR

Extend the get_read_block_error function in agent/file_safety.py to deny reads of sensitive credential files, such as auth.json and .anthropic_oauth.json, to prevent potential credential exfiltration.

Guidance

  • Review the get_read_block_error function to understand the current deny-listing logic and how to extend it to include the sensitive credential files.
  • Consider adding a helper function to centralize the deny-listed paths, making it easier to manage and extend in the future.
  • Test the changes thoroughly, including unit tests for the new deny-listed paths and regression tests for existing functionality.
  • Evaluate the proposed patch and unit tests provided in the issue to ensure they meet the requirements and do not introduce new issues.

Example

def get_read_block_error(path):
    # Existing deny-listing logic for skills/.hub/
    if path.startswith("skills/.hub/"):
        return "Cannot read skills/.hub/ directory"
    
    # Proposed extension to deny-list sensitive credential files
    if path in ["/auth.json", "/auth.lock", "/.anthropic_oauth.json"]:
        return "Credential store, cannot be read directly"
    
    # Allow reads for other paths
    return None

Notes

The provided patch and unit tests seem to address the issue, but it's essential to review and test them thoroughly to ensure they meet the requirements and do not introduce new issues.

Recommendation

Apply the proposed workaround by extending the get_read_block_error function to deny reads of sensitive credential files, as it directly addresses the identified security vulnerability and has been tested with a provided patch and unit tests.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix Security: read_file can exfiltrate credentials from auth.json and .anthropic_oauth.json [1 pull requests, 2 comments, 2 participants]