fix(security): keep model caches owner-only - #64202
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens Hermes’ local on-disk caches for model metadata and the remote model-catalog manifest by ensuring they are written with owner-only permissions (0600) instead of inheriting a potentially permissive process umask. This aligns these caches with other private Hermes state files and reduces the risk of local information disclosure.
Changes:
- Write the CLI model-catalog cache via the shared
atomic_json_write(...)helper and explicitly setmode=0o600. - Ensure the OpenRouter model metadata disk cache is saved with
mode=0o600. - Extend tests to validate 0600 permissions on POSIX platforms (while keeping content assertions on Windows).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
hermes_cli/model_catalog.py |
Routes cache writes through atomic_json_write and forces owner-only permissions. |
agent/model_metadata.py |
Sets owner-only permissions for the OpenRouter metadata disk cache. |
tests/hermes_cli/test_model_catalog.py |
Adds a POSIX-only assertion that the model-catalog cache file is written as 0600. |
tests/agent/test_model_metadata.py |
Adds a POSIX-only assertion that the OpenRouter metadata cache file is written as 0600. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if os.name != "nt": | ||
| assert stat.S_IMODE(cache_file.stat().st_mode) == 0o600 |
| if os.name != "nt": | ||
| assert stat.S_IMODE(cache_path.stat().st_mode) == 0o600 |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for hardening the two targeted cache writers. The proposed atomic_json_write(..., mode=0o600) mechanism is appropriate: utils.py:175-196 sets the temporary-file mode before replacement on POSIX and reapplies it to the resolved target.
Problems
- The hardening is incomplete for sibling persisted model caches.
agent/models_dev.py:235,hermes_cli/models.py:2727, andhermes_cli/models.py:4011useatomic_json_writewithoutmode=0o600;hermes_cli/models.py:861-884writes the Nous recommended-model cache through a default-mode temporary file. Those paths remain umask-dependent.
Suggested changes
- Apply the same owner-only mode to those writers, convert the Nous cache write to the shared atomic JSON helper, and add POSIX permission assertions for each persisted model-cache path.
This is an automated hermes-sweeper review.
| json.dump(data, fh, indent=2) | ||
| fh.write("\n") | ||
| atomic_replace(tmp, path) | ||
| atomic_json_write(path, data, indent=2, mode=0o600) |
There was a problem hiding this comment.
Please extend this owner-only write policy to the sibling persisted model caches: agent/models_dev.py:235, hermes_cli/models.py:2727, hermes_cli/models.py:4011, and the direct temporary-file write at hermes_cli/models.py:861-884 remain umask-dependent.
SummaryTen PRs were checked across the model-catalog cluster. #54737, #54793, and #54840 are the recorded best fixes for bounded provider/generic, manifest, and broad live-catalog reads respectively; #64202 instead hardens two persisted cache writers, while the other PRs address overlapping provider reads or separate validation, configuration, discovery, and picker behavior. Related pull requests
DuplicatesClosed #54765 and #56495 substantially duplicate the Suggested consolidationKeep #64202 open with a salvage path: preserve its two owner-only atomic cache writes, then address the contributor keep-open review by extending Cross-PR triage: Reviewed 10 pull requests and 4 issues in this complex. Each diff was read against this issue; Assessment working set: 74 kB of PR diffs, 26 kB of issue/PR text, 22 kB of discussion (28 comments), 16 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
|
suggesting changes The cache hardening is incomplete: fresh legacy cache files are accepted without an owner-only permission check. A pre-existing broad-permission catalog or OpenRouter metadata cache can remain readable and replaceable through fresh, stale/offline, or failed-refresh paths, allowing local peers to influence model metadata and selection.
Security evidence:
Review setup: I reviewed a run-owned local rebase or patch replay against current GitHub Not checked:
Signed: GPT-5.6-luna-max in Codex |
fix(security): keep model caches owner-only
|
Summary
0600permissionsWhy
These caches contain locally selected/provider-derived model metadata and previously inherited the process umask. Explicit owner-only modes align them with Hermes' other private state files.
Verification
scripts/run_tests.sh tests/agent/test_model_metadata.py tests/hermes_cli/test_model_catalog.pyruff checkpassedgit diff --checkpassed