fix(security): refuse to chmod(parent, 0o700) on / or top-level dirs (#25821)#29670
Merged
Conversation
Five call sites do os.chmod(path.parent, 0o700) without checking that the parent resolves to a safe directory. If HERMES_HOME or another path env var resolves to /, the chmod strips traversal permission from the root inode and bricks the entire host. Add secure_parent_dir() to hermes_constants.py that refuses to chmod / or any top-level directory (depth < 2). Replace all 5 call sites with this helper. Fixes #25821
- Drop two extra blank lines between display_hermes_home and secure_parent_dir - Fix docstring saying 'depth < 2' (actual guard is parts < 3)
Contributor
🔎 Lint report:
|
This was referenced May 21, 2026
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.
Salvages @liuhao1024's #25831 — production-confirmed P0 host-bricking bug. If any of the 5 token-storage paths resolves to a top-level dir (e.g.
HERMES_HOME=/),os.chmod("/", 0o700)succeeds and strips traversal perms from the root inode, taking out DNS / networking / journald / Docker containers.Closes #25821.
Summary
New
secure_parent_dir(path)helper refuses to chmod when the resolved parent is/or any direct child (/usr,/etc,/var, …) — the depth check (< 3) covers all top-level dirs without needing a hardcoded blocklist. Applied at all 5 known call sites.Changes
hermes_constants.py:secure_parent_dir()helpertools/mcp_oauth.py,hermes_cli/auth.py(3 sites),agent/google_oauth.py: route everyos.chmod(parent, 0o700)through the new helpertests/test_hermes_constants.py: 5 unit tests for the helperValidation
HERMES_HOME=/→ chmod /HERMES_HOME=/etc→ chmod /etcHERMES_HOME=/home/u/.hermes→ chmod /home/u/.hermesTargeted tests: 40/40 (hermes_constants), 148/148 (auth + mcp_oauth + google_oauth). E2E with real
secure_parent_diragainst 8 catastrophic paths (/,/usr/...,/etc/...,/tmp/...,/var/...,/home/...) all correctly skipped; safe nested paths still chmod 0o700.Other PRs on this issue
Infographic