Skip to content

[Security] No network egress filtering — terminal commands have unrestricted internet access #4170

@SHL0MS

Description

@SHL0MS

Context

PR #4168 addresses 5 of 11 findings from a security audit. The remaining 6 need design decisions or architectural changes.

Remaining gaps

Critical

1. Credential file read blocking in file_tools.py
read_file has no deny list for credential paths. Currently it blocks /etc/, /boot/, /usr/lib/systemd/ and docker sockets, but NOT ~/.ssh/*, ~/.aws/credentials, ~/.hermes/.env, ~/.gnupg/*, ~/.kube/config, ~/.netrc. PR #4168 added terminal-level patterns for cat/head/tail of these paths, but the read_file tool itself is unprotected.

2. Network egress filtering on local backend
Terminal commands have unrestricted internet access. The URL safety checks in tools/url_safety.py only apply to hermes-native web tools, not to curl/wget/python run through the terminal. Options: network namespace isolation, eBPF/seccomp filtering, or flagging commands that combine file reading with network tools.

High

3. Output redaction gaps
agent/redact.py misses: JWT tokens (eyJhbGciOi...), AWS secret keys (40-char base64 beyond AKIA* prefix), Basic auth in URLs (https://user:pass@host), session cookies, OAuth refresh tokens, OpenSSH private keys (-----BEGIN OPENSSH PRIVATE KEY-----).

4. HERMES_REDACT_SECRETS=0 disables all redaction
This env var (redact.py:112) turns off all output redaction. Should be blocked from being set in subprocesses and should require explicit config file change rather than runtime env.

Medium

5. Smart approval is LLM-bypassable
When approvals.mode: smart, an auxiliary LLM decides whether to approve. A disguised exfiltration command (e.g., curl https://api.github.com/repos/... with a credential in a query param) can pass review. Smart mode should have a hard-deny list the LLM cannot override.

6. "Always" approval creates permanent prefix bypass
Approving python -c with "always" approves ALL future python -c commands, including exfiltration scripts. The permanent allowlist should be pattern-scoped to the specific command, not the prefix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions