Skip to content

feat(security): deny writes to secondary shell startup files and global git config (Claude Code v2.1.160-inspired) - #45293

Closed
teknium1 wants to merge 1 commit into
mainfrom
claude-code-inspired/shell-startup-write-deny
Closed

feat(security): deny writes to secondary shell startup files and global git config (Claude Code v2.1.160-inspired)#45293
teknium1 wants to merge 1 commit into
mainfrom
claude-code-inspired/shell-startup-write-deny

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Writes to secondary shell startup files (~/.zshenv, ~/.zlogin, ~/.bash_login) and global git config (~/.gitconfig, ~/.config/git/) are now denied by the shared file-safety layer — closing the same persistence/code-execution gap Claude Code patched in v2.1.160.

Source

Claude Code changelog v2.1.160–2.1.161 (Jun 2, 2026): "Security: prompt before writing shell startup files (.zshenv, .bash_login) and ~/.config/git/" — https://code.claude.com/docs/en/changelog

How our implementation differs

Claude Code hermes-agent
Mechanism Permission prompt before write Hard deny in the shared write denylist (agent/file_safety.py), consistent with our existing .bashrc/.zshrc handling
Scope Startup files + ~/.config/git/ Same, plus ~/.gitconfig (classic location) and ~/.zlogin
Project-local .git/config n/a Intentionally NOT denied — legit workflow target (verified by test)

Why hard-deny instead of prompt: hermes already hard-denies the primary startup files (.bashrc, .zshrc, .profile, ...) via build_write_denied_paths(); the new entries are the same vector through less common files, so they get the same treatment. As documented in file_safety.py, this is defense-in-depth, not a security boundary — the terminal tool can still touch these with explicit shell commands (which go through dangerous-command approval).

Changes

  • agent/file_safety.py: +4 exact deny paths (.zshenv, .zlogin, .bash_login, .gitconfig), +1 prefix deny (~/.config/git/)
  • tools/skills_guard.py: zshenv added to the shell_rc_mod persistence regex
  • tests/tools/test_write_deny.py: new paths covered + project-local .git/config stays writable

Validation

Check Result
tests/tools/test_write_deny.py + 4 sibling file-safety test files 100 passed
E2E (write_file_tool with real imports, isolated HERMES_HOME) all 6 new paths denied, pre-existing file contents untouched; legit writes + project .git/config still work

@liuhao1024

Copy link
Copy Markdown
Contributor

Verification review — This PR was reviewed as part of a scheduled code review pass.

What was checked:

  • ✅ All new denied paths (.zshenv, .zlogin, .bash_login, .gitconfig) are correctly added to build_write_denied_paths()
  • ~/.config/git/ prefix denial covers XDG global git config + hooks (arbitrary code execution vector via core.hooksPath)
  • skills_guard.py regex updated to include zshenv — consistent with the path-level denial
  • ✅ Tests verify both positive (denied paths) and negative (project-local .git/config is NOT denied) cases
  • ✅ No false positives on legitimate project-local git config paths
  • ✅ Well-documented rationale referencing Claude Code v2.1.160 hardening

Verdict: Clean security hardening. The attack surface reduction is well-scoped — blocks secondary shell startup files that are equivalent persistence vectors to .bashrc/.zshrc, and guards global git config where core.hooksPath/credential.helper writes would be RCE on the next git command. Test coverage is thorough with both positive and negative cases.

@alt-glitch alt-glitch added type/security Security vulnerability or hardening P3 Low — cosmetic, nice to have comp/tools Tool registry, model_tools, toolsets tool/file File tools (read, write, patch, search) labels Jun 13, 2026
Block write tool edits to secondary shell startup files and global git config paths while preserving project-local `.git/config` writes.
@teknium1
teknium1 force-pushed the claude-code-inspired/shell-startup-write-deny branch from d756b7f to e2d80b6 Compare June 13, 2026 13:52
@teknium1

Copy link
Copy Markdown
Contributor Author

Refreshed against current origin/main and force-pushed a smaller salvage commit.

Cleanup:

  • reduced to 22 insertions / 2 deletions
  • exact write-deny for secondary shell startup files and global git config
  • prefix write-deny for ~/.config/git/
  • keeps project-local .git/config allowed
  • extends skills_guard persistence detection for .zshenv

Validation:

  • python3 -m pytest tests/tools/test_write_deny.py tests/agent/test_file_safety.py tests/agent/test_file_safety_credentials.py tests/agent/test_file_safety_cross_profile.py tests/agent/test_file_safety_container_mirror.py tests/agent/test_file_safety_sandbox_mirror.py tests/tools/test_skills_guard.py -> 177 passed
  • git diff --check -> passed

@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: claude-code-inspired/shell-startup-write-deny vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 10876 on HEAD, 10876 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 5708 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@teknium1

Copy link
Copy Markdown
Contributor Author

Closing per maintainer policy direction: Hermes should not keep expanding hardcoded write-deny lists for user-owned shell/Git config files. If users want filesystem containment, the intended boundary is Docker/remote backends, OS users, and permissions. Follow-up PR #45947 moves policy the other way by making shell startup files, package-manager configs, and Hermes control files writable again while keeping narrower blocks for SSH keys, .env/OAuth token stores, mcp-tokens, pairing state, and privileged system files.

@teknium1 teknium1 closed this Jun 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have tool/file File tools (read, write, patch, search) type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants