security: harden subprocess isolation, add exfiltration detection, fix YOLO bypass#4168
Closed
SHL0MS wants to merge 1 commit into
Closed
security: harden subprocess isolation, add exfiltration detection, fix YOLO bypass#4168SHL0MS wants to merge 1 commit into
SHL0MS wants to merge 1 commit into
Conversation
Collaborator
Author
|
Ref #4170 — remaining security gaps (credential file read blocking, network egress, redaction expansion, smart approval hard-deny, always-approval scoping, HERMES_REDACT_SECRETS) tracked there. |
78f190f to
020e65b
Compare
4 tasks
…x YOLO bypass Five security improvements from audit: 1. Block cloud provider credentials from subprocesses: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AZURE_CLIENT_SECRET, GOOGLE_APPLICATION_CREDENTIALS, KUBECONFIG, SSH_AUTH_SOCK, and 10 more added to env blocklist. 2. Add data exfiltration patterns to DANGEROUS_PATTERNS: netcat to external IPs, bash /dev/tcp and /dev/udp, openssl s_client, curl with data upload, wget with POST data, and credential file reads via cat/head/tail/less/more/bat targeting .ssh/, .env, .gnupg/, etc. 3. Change tirith default from fail_open=True to fail_open=False. When the tirith binary is not installed (common), all security checks were silently skipped. 4. Cache HERMES_YOLO_MODE at import time so subprocesses cannot export it to bypass approval in subsequent commands within the same session. 5. Set GIT_TERMINAL_PROMPT=0 and GIT_CONFIG_GLOBAL=/dev/null in all subprocess environments to prevent malicious repos from executing hooks or prompting for credentials on clone.
020e65b to
9a2c801
Compare
win4r
added a commit
to win4r/hermes-agent
that referenced
this pull request
Apr 9, 2026
Reading `~/.ssh/config` via the `read_file` tool previously echoed the
entire contents verbatim, leaking:
- `IdentityFile` paths (tells an attacker exactly which key files to
steal — the single most valuable piece of info for credential theft)
- `ProxyJump` / `ProxyCommand` (enumerates internal bastion hosts and
the exact commands needed to reach protected networks)
- `IdentityAgent` / `CertificateFile` (similar metadata exposure)
PR NousResearch#4168 adds an approval-prompt pattern for `cat`/`head`/`tail` on
`.ssh/`, which covers the terminal-tool path. This patch adds the
complementary fix for the `read_file` path: sensitive directives are
masked via the existing `redact_sensitive_text` pipeline that already
handles API keys, tokens, and private key blocks.
The redaction is surgical by design. `Host`, `HostName`, `User`, and
`Port` remain visible because they are frequently needed for legitimate
debugging (and leaking them alone — without the identity file path —
does not materially help an attacker who already has read access).
Matching is case-insensitive per sshd_config(5) and multiline-aware so
each config line is evaluated independently. Values are replaced with
`***` so the structure of the config (which keywords are set, and
where) stays visible.
Tests: `tests/agent/test_redact.py::TestSSHConfigRedaction` (10 cases)
covering each directive, case-insensitivity, full-config structure
preservation, and a negative case ensuring prose mentions of the
keyword are NOT incorrectly redacted.
This was referenced Apr 9, 2026
SHL0MS
added a commit
to SHL0MS/hermes-agent
that referenced
this pull request
Apr 11, 2026
Add patterns for: netcat to external IPs, bash /dev/tcp and /dev/udp, openssl s_client, curl with data upload, wget with POST data, and credential file reads via cat/head/tail/less/more/bat targeting .ssh/, .env, .gnupg/, .kube/config, .netrc, aws/credentials. These trigger approval prompts, not hard blocks. Ref NousResearch#4170. Split from NousResearch#4168.
SHL0MS
added a commit
to SHL0MS/hermes-agent
that referenced
this pull request
Apr 11, 2026
… bypass HERMES_YOLO_MODE was read via os.getenv() on every approval check. A persistent shell session could export it to bypass approval in subsequent commands. Now cached as _YOLO_AT_STARTUP at module import. Updated 3 tests to monkeypatch the cached constant. Ref NousResearch#4170. Split from NousResearch#4168.
Collaborator
Author
|
Split into 3 focused PRs for easier review:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Four security improvements from a systematic audit of the agent's subprocess isolation and command approval system.
1. Block cloud provider credentials from subprocesses
The env blocklist in
local.pywas missing major cloud provider credentials. Added:AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN,AZURE_CLIENT_SECRET,AZURE_CLIENT_ID,AZURE_TENANT_ID,GOOGLE_APPLICATION_CREDENTIALS,KUBECONFIG,DOCKER_HOST,DOCKER_CERT_PATH,SSH_AUTH_SOCK,NPM_TOKEN,PYPI_TOKEN,GPG_AGENT_INFO.2. Add data exfiltration patterns to DANGEROUS_PATTERNS
The existing patterns only covered destructive operations. Zero coverage for outbound data transfer. Added: netcat to external IPs, bash
/dev/tcpand/dev/udp,openssl s_client,curlwith data upload,wgetwith POST data, and credential file reads viacat/head/tail/less/more/battargeting.ssh/,.env,.gnupg/,.kube/config.These trigger approval prompts, not hard blocks — the user can still approve if intentional.
3. YOLO_MODE: cached at import, not inherited
HERMES_YOLO_MODEwas read fromos.getenv()on every approval check. A persistent shell session couldexport HERMES_YOLO_MODE=1and all subsequent commands would bypass approval. Now cached as_YOLO_AT_STARTUPat module import time.4. Git hardening: GIT_TERMINAL_PROMPT=0
Set
GIT_TERMINAL_PROMPT=0in all subprocess environments to prevent git from prompting for credentials on clone. We do NOT setGIT_CONFIG_GLOBAL=/dev/nullbecause that would disable credential helpers, user aliases, and all user git config.What was removed from the original PR
Tirith fail_open=True → False— Reverted. Tirith is rarely installed; fail_closed would block ALL terminal commands for most users.GIT_CONFIG_GLOBAL=/dev/null— Removed. This disabled the user's entire git config (credential helpers, aliases, diff tools). OnlyGIT_TERMINAL_PROMPT=0is set.Changes
49 insertions, 2 deletions across
tools/approval.py,tools/environments/local.py.Ref #4170