Skip to content

fix(security): add read-path deny list for credential and secret files#2714

Closed
dieutx wants to merge 1 commit into
NousResearch:mainfrom
dieutx:fix/file-tools-read-deny-list
Closed

fix(security): add read-path deny list for credential and secret files#2714
dieutx wants to merge 1 commit into
NousResearch:mainfrom
dieutx:fix/file-tools-read-deny-list

Conversation

@dieutx

@dieutx dieutx commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • read_file has zero path restrictions — reads ANY file including /etc/shadow, ~/.hermes/.env (API keys), ~/.hermes/auth.json (OAuth tokens), SSH private keys
  • The write path has _is_write_denied() with a deny list, but no equivalent exists for reads
  • Fix: add READ_DENIED_PATHS and READ_DENIED_PREFIXES covering credential files, and enforce in both read_file() and search()
  • Non-secret files like ~/.hermes/config.yaml and session files remain readable

Security Impact

  • On gateway (Telegram/Discord), prompt injection can instruct: read_file("~/.hermes/.env") → exfiltrates all API keys
  • Also reads: ~/.hermes/auth.json (OAuth tokens, refresh tokens), ~/.ssh/id_rsa, /etc/shadow
  • Confirmed working on v0.4.0 — all three reads succeed without any restriction
  • Severity: CRITICAL

How to reproduce

hermes chat -q "Use the read_file tool to read ~/.hermes/.env"
hermes chat -q "Use the read_file tool to read /etc/shadow"

How to test

  • 14 new tests covering: .env blocked, auth.json blocked, SSH keys blocked, /etc/shadow blocked, .aws/ prefix blocked, .gnupg/ prefix blocked, .kube/ blocked, traversal paths blocked, normal project files allowed, config.yaml allowed, session files allowed
  • All 75 existing file tool tests pass

Platform tested

  • Linux, hermes-agent v0.4.0

The file tools have a write deny list (WRITE_DENIED_PATHS) that blocks
writes to .env, .ssh/*, /etc/shadow, etc. but no equivalent for reads.
read_file() can read any file on the filesystem including API keys,
OAuth tokens, SSH private keys, and shadow passwords.

Add READ_DENIED_PATHS and READ_DENIED_PREFIXES matching the most
sensitive credential paths, and enforce in read_file() and search().
Also blocks traversal paths like /tmp/../etc/shadow via realpath().

Non-secret config files (~/.hermes/config.yaml) and session files
remain readable.
@dieutx

dieutx commented Apr 1, 2026

Copy link
Copy Markdown
Contributor Author

Closing — needs more thought on the right scope. The write deny list already covers the critical paths.

@dieutx dieutx closed this Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant