fix(security): guard os.chmod(parent) against / and top-level dirs#25831
Closed
liuhao1024 wants to merge 1 commit into
Closed
fix(security): guard os.chmod(parent) against / and top-level dirs#25831liuhao1024 wants to merge 1 commit into
liuhao1024 wants to merge 1 commit into
Conversation
cb3e7c7 to
a57dda4
Compare
a57dda4 to
0857a5a
Compare
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 NousResearch#25821
0857a5a to
4b3f64d
Compare
Contributor
|
Wait — your PR was actually salvaged. Disregard, this comment is in error. |
Contributor
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.
Summary
Five call sites do
os.chmod(path.parent, 0o700)on a derived path without checking that the parent resolves to a safe directory. IfHERMES_HOMEor another path env var resolves to/, the chmod strips traversal permission from the root inode and bricks the entire host — every non-root user fails any path lookup withEACCES, taking out DNS, networking, journald, and every Docker container that drops privileges.This was hit in production (see #25821). Root cause took 5+ hours to isolate.
Root Cause
All 5 call sites share this pattern:
os.chmod("/", 0o700)raises no exception — it succeeds.Fix
Add
secure_parent_dir(path)tohermes_constants.pythat refuses to chmod/or any top-level directory (depth < 2 resolved parts). Replace all 5 call sites:tools/mcp_oauth.py:179—_write_json(MCP OAuth tokens)hermes_cli/auth.py:991—_save_auth_storehermes_cli/auth.py:1573—_save_qwen_cli_tokenshermes_cli/auth.py:2991—_save_nous_shared_tokenagent/google_oauth.py:495—save_credentialsCode Intelligence
secure_parent_dir(new function),_save_auth_store,_write_json,save_credentials/and top-level dirs; all normal paths behave identically_secure_dir()incron/jobs.py(addresses~/.hermesonly, not the 5 credential sites)Regression Coverage
6 new tests in
tests/test_hermes_constants.py::TestSecureParentDir:test_safe_path_calls_chmod— normal nested path (depth ≥ 3) calls os.chmodtest_root_dir_skipped—/is never chmod'dtest_top_level_dir_skipped—/usrand similar depth-2 dirs are never chmod'dtest_two_component_path_skipped— paths with < 3 resolved parts are skippedtest_oserror_suppressed— OSError from chmod is silently caughttest_symlink_resolved— symlinks are resolved before depth checkTesting
tests/test_hermes_constants.py— 40 passed (includes all 6 new tests)tests/hermes_cli/test_auth_toctou_file_modes.py— 4 passed (existing auth chmod tests)tests/tools/test_mcp_oauth.py— 38 passed (existing OAuth tests)Fixes [bug] os.chmod(path.parent, 0o700) bricks host when path.parent resolves to / #25821