Summary
agent/file_safety.py:get_read_block_error() on origin/main blocks Hermes internal hub cache files, but still allows reads of common project-local environment files such as:
.env
.env.local
.env.development
.env.production
.env.test
.env.staging
.envrc
Because both top-level read_file and the Copilot ACP fs/read_text_file path consult this helper, the missing policy leaks through both surfaces.
Current origin/main behavior
On origin/main, get_read_block_error() only blocks internal hub cache paths:
def get_read_block_error(path: str) -> Optional[str]:
"""Return an error message when a read targets internal Hermes cache files."""
resolved = Path(path).expanduser().resolve()
hermes_home = _hermes_home_path().resolve()
blocked_dirs = [
hermes_home / "skills" / ".hub" / "index-cache",
hermes_home / "skills" / ".hub",
]
...
return None
There is no deny rule for project-local secret-bearing env basenames.
Why this matters
Even if home-directory credential paths and HERMES_HOME credential stores are handled separately by other open work, the most common place application secrets live in real repositories is the project directory itself:
./.env
./services/api/.env.production
./web/.env.local
Today those files are still readable through the shared read guard helper.
Because ACP reuses the same helper (agent/copilot_acp_client.py calls get_read_block_error() before fs/read_text_file), this is not just a read_file issue — it also affects ACP file reads inside the workspace.
Reproduction
On origin/main:
from agent.file_safety import get_read_block_error
print(get_read_block_error("/tmp/project/.env"))
print(get_read_block_error("/tmp/project/.env.production"))
print(get_read_block_error("/tmp/project/.env.local"))
Actual behavior
All return None, so the read is allowed.
Likewise, top-level read_file("/tmp/project/.env.production") proceeds instead of being denied.
Expected behavior
Common secret-bearing env files inside arbitrary project directories should be denied by the shared read guard helper, while obviously non-secret examples such as .env.example should remain readable.
Suggested basename deny set:
.env
.env.local
.env.development
.env.production
.env.test
.env.staging
.envrc
Allowed example:
Why this is distinct from existing reports
This is related to, but not the same as:
Those are valuable, but they do not address the project-local .env* basename gap in the central helper on origin/main.
Suggested fix
Extend agent/file_safety.py:get_read_block_error() with a basename check for common secret-bearing project env files, using the resolved filename only (not a hardcoded directory), for example:
blocked_project_env_names = {
".env",
".env.local",
".env.development",
".env.production",
".env.test",
".env.staging",
".envrc",
}
if resolved.name.lower() in blocked_project_env_names:
return "Access denied ..."
This keeps the policy centralized so both:
tools/file_tools.py:read_file_tool, and
agent/copilot_acp_client.py:fs/read_text_file
benefit automatically.
Validation we performed locally
A local patch extending the helper and re-verifying both call paths passed:
python3 -m py_compile agent/file_safety.py \
tests/agent/test_copilot_acp_client.py \
tests/tools/test_file_read_guards.py \
tests/agent/test_file_safety.py
python3 -m pytest -o addopts='' \
tests/agent/test_copilot_acp_client.py \
tests/tools/test_file_read_guards.py \
tests/agent/test_file_safety.py -q
Result:
The added coverage specifically proved:
- internal Hermes hub cache reads are denied
- sensitive home dirs such as
~/.ssh are denied
- project secret files such as
.env and .env.production are denied
- ACP file reads respect the same shared guard
- normal files and
.env.example remain allowed
Summary
agent/file_safety.py:get_read_block_error()onorigin/mainblocks Hermes internal hub cache files, but still allows reads of common project-local environment files such as:.env.env.local.env.development.env.production.env.test.env.staging.envrcBecause both top-level
read_fileand the Copilot ACPfs/read_text_filepath consult this helper, the missing policy leaks through both surfaces.Current origin/main behavior
On
origin/main,get_read_block_error()only blocks internal hub cache paths:There is no deny rule for project-local secret-bearing env basenames.
Why this matters
Even if home-directory credential paths and HERMES_HOME credential stores are handled separately by other open work, the most common place application secrets live in real repositories is the project directory itself:
./.env./services/api/.env.production./web/.env.localToday those files are still readable through the shared read guard helper.
Because ACP reuses the same helper (
agent/copilot_acp_client.pycallsget_read_block_error()beforefs/read_text_file), this is not just aread_fileissue — it also affects ACP file reads inside the workspace.Reproduction
On
origin/main:Actual behavior
All return
None, so the read is allowed.Likewise, top-level
read_file("/tmp/project/.env.production")proceeds instead of being denied.Expected behavior
Common secret-bearing env files inside arbitrary project directories should be denied by the shared read guard helper, while obviously non-secret examples such as
.env.exampleshould remain readable.Suggested basename deny set:
.env.env.local.env.development.env.production.env.test.env.staging.envrcAllowed example:
.env.exampleWhy this is distinct from existing reports
This is related to, but not the same as:
~/.ssh,~/.aws, etc.)auth.json,.anthropic_oauth.json)Those are valuable, but they do not address the project-local
.env*basename gap in the central helper onorigin/main.Suggested fix
Extend
agent/file_safety.py:get_read_block_error()with a basename check for common secret-bearing project env files, using the resolved filename only (not a hardcoded directory), for example:This keeps the policy centralized so both:
tools/file_tools.py:read_file_tool, andagent/copilot_acp_client.py:fs/read_text_filebenefit automatically.
Validation we performed locally
A local patch extending the helper and re-verifying both call paths passed:
python3 -m py_compile agent/file_safety.py \ tests/agent/test_copilot_acp_client.py \ tests/tools/test_file_read_guards.py \ tests/agent/test_file_safety.py python3 -m pytest -o addopts='' \ tests/agent/test_copilot_acp_client.py \ tests/tools/test_file_read_guards.py \ tests/agent/test_file_safety.py -qResult:
49 passed, 1 warningThe added coverage specifically proved:
~/.sshare denied.envand.env.productionare denied.env.exampleremain allowed