Hermes Agent

Hermes strips inherited credentials before child processes start

Hermes proposes removing the BWS token and every password-shaped variable from child-process environments, backed by a campaign inventory of process launch sites. A related gateway patch also addresses file-descriptor exhaustion across restart, shutdown and SSH launch paths.

← Back to homeOriginal source ↗

NousResearch/hermes-agent PR #77027 is the inspected primary source: “fix(security): strip BWS token and *_PASSWORD from child-process envs.” The related records below were inspected as supporting context rather than independent confirmation.

The facts

- NousResearch/hermes-agent PR #77027 was created 2026-08-02T18:52:46Z and was open at inspection; its title is “fix(security): strip BWS token and *_PASSWORD from child-process envs.” - NousResearch/hermes-agent issue #83565 was created 2026-08-11T01:00:22Z and was open at inspection; its title is “[Campaign EPIC] Child-process credential-inheritance conquest.” - NousResearch/hermes-agent PR #83542 was created 2026-08-11T00:19:05Z and was open at inspection; its title is “fix(gateway,desktop,dashboard): EMFILE follow-up — restart-path gateway reap, shutdown cleanup, SSH ulimit, scandir.” - The repository reported 228467 stars, 30633 open issues, default branch main, and last push 2026-08-11T01:00:28Z. - The latest tagged-release baseline checked was v2026.8.3 published 2026-08-03T16:57:52Z.

What changed

NousResearch/hermes-agent PR #77027 reports: What changed and why Closes the child-process credential-inheritance bug class where trusted Hermes credentials and other sensitive parent-environment values reached untrusted or model-authored subprocesses. Confirmed production chain (pinned head de0e88d8):** SingularityEnvironment._run_bash → _popen_bash with no sanitized env → subprocess.Popen inherited the trusted Hermes process environment. Docker, SSH, and future backends converge on the same shared boundary, so safety cannot depend on every caller remembering to pass env. Changes **tools/environments/base.py** — _popen_bash now builds a sanitized child env by default (build_subprocess_env(base=...)) and applies the same policy to caller-supplied env maps, so omitting env can never re-open ambient inheritance. **tools/environments/local.py** — case-insensitive provider/security matching (_is_blocked_provider_env) for Windows environment semantics; effective destination keys behind APPTAINERENV_/SINGULARITYENV_ wrappers are checked (_credential_target_env_name); BWS_ACCESS_TOKEN promoted to Tier-1 _ALWAYS_STRIP_KEYS so inherit_credentials=True paths cannot export the vault bootstrap token. **tools/environments/singularity.py** — preflight, instance start, image build, and cleanup subprocesses all use the sanitized builder; image construction re-adds ONLY the six explicit Apptainer/Singularity Docker registry-auth variables instead of the full parent environment. **tools/environments/docker.py** — explicit docker_forward_env entries may not export Hermes-internal secrets (AUXILIARY_*/GATEWAY_RELAY_*/BWS_ACCESS_TOKEN) — the

NousResearch/hermes-agent issue #83565 reports: [Campaign EPIC] Child-process credential-inheritance conquest Meta-issue for the class anchored by #77027.** Every open PR and issue that fixes the same bug — trusted Hermes credentials and other sensitive parent-environment values reaching untrusted or model-authored child processes — is bound here, with its live state, interlock status, and merge order. This is the coordination surface (Meta-Lock): dedup first, interlock every node, merge in dependency order, keep the table current. The class Invariant:** a spawned child process (terminal command, Docker/SSH/Singularity backend, browser worker, ACP executor, LSP server, plugin sidecar, installer, model-driving CLI, desktop PTY) must never inherit trusted Hermes credentials from the parent environment unless a narrow explicit passthrough contract applies. Confirmed production chain (anchor PR #77027, pinned vulnerable head de0e88d8):** SingularityEnvironment._run_bash → _popen_bash with no sanitized env → subprocess.Popen inherited the trusted Hermes process environment. Docker, SSH, and future backends converge on the same shared boundary. The anchor fix (merged state: OPEN, clean, CI green):** _popen_bash sanitizes by default; case-insensitive blocking for Windows semantics; APPTAINERENV_/SINGULARITYENV_ wrapper tunneling closed; BWS_ACCESS_TOKEN promoted to Tier-1 always-strip; Docker explicit

NousResearch/hermes-agent PR #83542 reports: Summary Closes the surviving halves of the EMFILE follow-up cluster after #83406: orphan gateways are now reaped on the restart path (not just serve startup), the Desktop-owned gateway restart child is terminated when its serve backend shuts down, SSH-spawned remote backends get ulimit -n 65536 before exec (launchd/plist limits never reach that spawn path), and five dashboard hot-path Path.iterdir() calls become context-managed os.scandir() so an exception mid-iteration can't leak directory fds into the sidebar poll loop. Fixes #77276, fixes #81547. Changes hermes_cli/web_server.py: _spawn_gateway_restart() reaps unsupervised gateway orphans before spawning (salvaged from #77721 by @RelaxJonh); lifespan shutdown terminates a live Desktop-managed gateway-restart child (salvaged from #77297 by @QuarkAssistant); 5 iterdir→scandir conversions in sidebar/checkpoints/file-manager/plugin-discovery paths (salvaged from #81619 by @smfworks) apps/desktop/electron/remote-lifecycle.ts: SSH spawn command prefixes ulimit -n 65536 2>/dev/null || true; exec... (salvaged from #82909 by @a-espinoza) #81619's separate _raise_fd_soft_limit() was folded into the canonical resource_limits.apply_nofile_soft_limit() from #83406 rather than duplicated; its source-regex tests were dropped per the no-source-reading-tests rule (behavior is covered by the endpoint tests) Follow-up: isolated _ACTION_PROCS in the #52470 spawn test whose

Why it matters

A process boundary is not isolation if children inherit the parent’s credential universe. Resource exhaustion belongs in the same audit because emergency restart paths are where broad environments and stale descriptors tend to escape review. The operator test is whether visible output, retained state and authority still describe the same event after retries, background work or restart.

Current

The primary record was open when captured on 2026-08-11. The tagged-release baseline was v2026.8.3 published 2026-08-03T16:57:52Z. Repository metadata, full source bodies, current pull requests and issues, releases, Google News, Hacker News, Lobsters, Metamesh and the rendered ClawCharts row were inspected. ClawCharts selected the subject; it did not prove the claim.

Evidence

The primary URL is https://github.com/NousResearch/hermes-agent/pull/77027. Supporting records are https://github.com/NousResearch/hermes-agent/issues/83565 and https://github.com/NousResearch/hermes-agent/pull/83542. Source bodies, timestamps and states are preserved in the daily evidence bundle. Test counts and reproductions remain attributed to their authors unless identified as independently rerun.

Source boundary

Open work is described as open, closed work as closed, and operator reports as reports. A pull request is evidence of proposed or reviewed direction, not proof of a shipped release. Search residue, package mirrors and historically published source spines were excluded.

Operator take

Construct child environments from allowlists, inventory every spawn site, and verify restart cleanup independently rather than assuming a launcher exit means custody ended. Preserve a before-state receipt, make the smallest reversible change, and verify the original failure independently.

Caveat

Public project records are mutable. Status, scope and evidence can change after publication. This brief records the inspected state and does not authorize changes to a reader’s deployment.

Source inspected; source state, environment and release boundary remain explicit.