fix(profiles): prevent credential leaks and SQLite data loss in exports - #35601
fix(profiles): prevent credential leaks and SQLite data loss in exports#35601keiranhaax wants to merge 6 commits into
Conversation
|
Verified the scope and correctness of this fix. A few specific confirmations: Both export paths covered: The Regex avoids false positives on non-credential files: Case-insensitive: the Nested backups caught: the ignore callback runs at every LGTM. |
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved ✅
Review
This PR fixes a genuine security gap where profile exports could leak credential backups (config.yaml.bak*, .env.bak*, etc.) that were not caught by the old exclusion list.
✅ Looks Good
- Comprehensive approach: Single
_is_sensitive_export_name()helper used by both default and named profile export paths, preventing future drift. - Well-considered edge cases: Distinguishes
.env.example(safe) from.env.local(sensitive), handles case-insensitivity, credential keyword matching bounded by delimiters to avoid false positives ontokenizer.json. - Thorough test coverage: Parametrized unit tests for 25+ sensitive and safe name patterns, plus integration tests for both export paths verifying nested backup exclusion.
- Clean diff: 124 additions, only 4 deletions — minimal change to existing logic, mostly new helper + tests.
- No security concerns detected: No hardcoded secrets, no SQL injection vectors, no path traversal issues.
Checklist Summary
| Category | Status |
|---|---|
| Correctness | ✅ Edge cases handled (nested backups, case-insensitive, keyword boundary) |
| Security | ✅ Fixes the exact security gap described |
| Code Quality | ✅ Clean helper, single source of truth, well-documented |
| Testing | ✅ Unit + integration, sensitive and safe paths, both export modes |
| Performance | ✅ O(n) per export, no concerns |
Reviewed by Hermes Agent (cron job)
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved ✅ — Fix profile export to exclude backup credentials from exports. Well-scoped, no security concerns.
Reviewed by Hermes Agent
2fd0f23 to
23f47c3
Compare
|
Refreshed this PR against current Current state:
Focused tests passed locally: uv run --with pytest python -m pytest tests/hermes_cli/test_profile_export_credentials.py tests/hermes_cli/test_profiles.py -o 'addopts=' -q
# 208 passed in 1.62sReady for maintainer review. |
|
Thanks for addressing a real export-security gap: current named-profile export only excludes exact Problems
Suggested changes
Automated hermes-sweeper review. |
3c7bd51 to
e7b1eca
Compare
|
Updated this PR against current Changes:
Validation: uv run --with pytest python -m pytest tests/hermes_cli/test_profile_export_credentials.py tests/hermes_cli/test_profiles.py -o 'addopts=' -q
# 231 passedThe branch is now 1 commit ahead and 0 behind |
e7b1eca to
30b2ff8
Compare
30b2ff8 to
51d9f7f
Compare
|
External review — blockers found on exact head The structural filtering and WAL-consistent SQLite snapshot work are valuable, and the staged
Focused suite: Suggested direction: atomically create output as a new regular file; establish one consistent export/import symlink policy; classify I intended this as a request-changes review, but GitHub does not allow this account to submit that review state without explicit repository access. |
Profile exports staged credential files by exact name only (.env, auth.json), so every config/env/auth *backup* Hermes writes during normal operation slipped into the archive: - hermes_cli/setup.py -> config.yaml.bak.<ts> - hermes_cli/xai_retirement.py -> config.yaml.bak-pre-migrate-xai-<ts> - other rewrites -> config.yaml.bak-<reason>-<ts>, .env.bak-<...> Add a shared _is_sensitive_export_name() classifier and route both the default-profile and named-profile export paths through it, matched at any directory depth. It excludes .env / .env.* (keeping .env.example/.sample/ .template/.dist), config.yaml.bak* / auth.json.* / auth.lock.* backups, private keys/keystores, SSH private keys, and credential-/token-looking containers, while leaving ordinary profile files (config.yaml, SOUL.md, docs, skills) intact. Tests cover the classifier plus default and named export archives. (cherry picked from commit 2fd0f2319fa191f3964cd4b603848bce3d67eed3)
8e21ae5 to
9e37ae1
Compare
|
Updated this PR against current Changes now cover:
The branch was rebased onto current Validation on exact head
GitHub now reports the PR as mergeable with no conflicts. Ready for maintainer review. |
|
too large to review safely This PR changes 1161 production lines before tests and docs. Please split it or add a focused justification if it should stay together. Signed: GPT-5.6-luna-high in Codex |
|
Thanks for flagging the reviewability concern. I kept the security fix atomic, but reorganized the production code so the boundary can be reviewed in focused sections. Reviewability update on exact head
|
|
I found one small change here that seems useful independently of profile export. On current Would you be open to extracting that shared-redactor fix and its focused tests into a small standalone PR? I’m happy to help reproduce or review it. |
|
Thanks for the focused suggestion. I extracted the independently useful shared-redactor change into #85762:
I kept the seven interdependent profile-export protections together in this PR. Once the standalone redactor fix lands, this branch can be rebased and the duplicated shared-redactor change removed. |
|
Real-world confirmation from a stopped named profile on Hermes v0.20.5: I also confirmed current |
|
Follow-up to the real-world reproduction above: I opened focused PR #93995 for the uncovered staged- |
Summary
Current
mainincludes #83458, which force-redacts recognized secret-shaped strings in supported text files before profile archives are written. That substantially reduces risk, but it does not fully enforce the profile-export security boundary.Named-profile exports still exclude only the exact files
auth.jsonand.env. Backups, renamed credential stores, opaque authorization state, private-key formats, binary databases, and sensitive caller-supplied extras can still enter a portable archive without matching the text redactor.This PR complements #83458 by adding structural path/type filtering before archive creation while retaining its final text-scrubbing pass.
What this fixes
.ppk, and keystore formats while preserving public certificates.extra_files..db,.sqlite, and.sqlite3databases before omitting WAL/SHM/journal sidecars.Security impact
Profile exports are intended to be portable and shareable. Exploitation requires a user to create and expose an archive, so this is not a passive remote vulnerability. However, affected archives can contain live credentials, private keys, pairing authorization state, or inconsistent database contents. Avoiding or manually sanitizing exports is the current workaround.
Validation
The branch is 3 commits ahead, 0 behind current
main, with contributor authorship preserved and no merge conflicts.