fix(security): salvage #25726 + #20778 .env protections#32011
Merged
Conversation
…sites .env holds API keys and secrets. Multiple creation sites used `cp` / `touch` / `shutil.copy2` which obey the process umask — commonly 0o022, leaving the file at 0o644 (world-readable). Apply chmod 0o600 explicitly at every site that creates or copies .env. Sites covered: - docker/stage2-hook.sh: after the seed_one '.env' call, applied unconditionally (not just on first-seed) so a host-mounted .env with loose perms gets tightened on every container restart - hermes_cli/doctor.py: 'hermes doctor --fix' touches an empty .env when missing - hermes_cli/profiles.py: 'hermes profile create --clone' copies .env from the source profile; shutil.copy2 preserves source mode, so a source .env at 0o644 was being cloned into 0o644 - setup-hermes.sh: in-tree setup script's cp .env.example .env path, plus the already-exists branch (mirror of install.sh which already chmods 600 unconditionally on line 1442) scripts/install.sh was NOT changed — it already chmod 600's the .env unconditionally after the create/already-exists branches (line 1442). Salvaged from PR #25726 by @dusterbloom. The docker/entrypoint.sh portion of the original PR was dropped because main switched to an s6-overlay shim — the .env creation logic moved to stage2-hook.sh, which is where the chmod now lives. Closes #25497 (subset — install.sh + setup-hermes.sh) and #8448 (subset — install.sh only) as superseded. Co-authored-by: teknium1 <127238744+teknium1@users.noreply.github.com>
get_read_block_error() only blocked internal Hermes cache files but allowed reading project-local secret-bearing environment files (.env, .env.production, .env.local, etc.) through both read_file and ACP fs/read_text_file paths. Add a basename deny set for common secret-bearing .env variants. .env.example remains readable as documentation. Fixes #20734
This was referenced May 25, 2026
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
unresolved-import |
1 |
First entries
tests/agent/test_file_safety.py:11: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
✅ Fixed issues: none
Unchanged: 4908 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
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.
Salvage of two stale .env-related PRs that conflicted with current main.
Commits (rebased, contributor authorship preserved)
@dusterbloom — fix(security): tighten .env file permissions to 0600 at all creation sites (fix(security): tighten .env file permissions to 0600 at all creation sites #25726)
Covers docker/stage2-hook.sh (post-s6-overlay refactor), hermes_cli/doctor.py (
--fixempty .env), hermes_cli/profiles.py (profile create --clonecopy), and setup-hermes.sh. scripts/install.sh already chmods 600 unconditionally (line 1442) — no change needed there.@liuhao1024 — fix(security): block read_file on project-local .env files (fix(security): block read_file on project-local .env files #20778)
Adds project-local
.env/.env.local/.env.development/.env.production/.env.test/.env.staging/.envrcto the read-deny list inagent/file_safety.py. Hermes-own.envwas already read-blocked; project-local.envwas not. Per the module docstring this is defense-in-depth, not a boundary (terminal can stillcat).Salvage tweaks
test_identically_named_files_outside_hermes_home_not_blockedwhich asserted project-local .env should be readable — that's exactly the assumption this PR inverts. Renamed totest_identically_named_hermes_files_outside_home_not_blockedand narrowed its assertions to auth.json / google_oauth.json / mcp-tokens/ which remain per-location gated.Test plan
Co-authored-by: dusterbloom 32869278+dusterbloom@users.noreply.github.com
Co-authored-by: liuhao1024 liuhao1024@users.noreply.github.com
Closes #25726
Closes #20778