fix(secrets): close redaction gaps - env-name variants, control-char splits, process(list) - #77768
thatssoheil wants to merge 4 commits into
Conversation
…splits, process(list) - _ENV_ASSIGN_RE / _SECRET_CFG_NAMES now recognize bare KEY/PASS/PW suffixes (FAL_KEY, MYSQL_PASS, DB_PW) and lowercase .env keys via the guarded config passes; prose (author=, monkey=, keyboard=) untouched. - redact_sensitive_text strips C0 controls (except \n/\t) and zero-width chars before matching, and normalizes \r -> \n, so secrets split by ESC/CR/zero-width no longer escape every regex. - process(action=list) now wraps entries in _redact_process_result via _redact_process_list, matching poll/log/wait. Closes NousResearch#77484.
…ch#55319, NousResearch#55321) A masked secret's visible head/tail could carry control bytes (newline, NUL, DEL, C1 0x80-0x9F, zero-width) into config/status/dump output. Strip every control incl. \n/\t (display differs from redact_sensitive_text, which preserves \n/\t as line structure) before slicing; all-control values return the configured empty fallback. Consolidates the previously-closed NousResearch#58079 approach (strip controls before masking) - supersedes it.
…#77484) _write_checkpoint persisted s.command verbatim to ~/.hermes/processes.json. Recovery only uses command for display/logging (the process is already running; adoption re-validates PID + start time, never re-runs the command), so masking is lossless.
Review cleanup: _HAS_CR_RE was defined but never used (the C0 class already covers \r, and the call site guards \r inline). The 'gate + full pattern' comment referenced a gate that no longer exists.
|
Thanks for the consolidation nudge — I agree, and I've folded #55319/#55321 into this PR. What I added:
Verified on current main that #55319 and #55321 are both still open (prior PR #58079 was closed, not merged), so this closes the gap they describe. Updated the PR body to note both are fixed by this change. Also pushed a review-cleanup commit (dead |
|
Merged via #80965, which combined this PR with your #80643 — your authorship is preserved on main for all four commits. What survived from each: #80643's implementation was taken for the shared #77484 scope (its span-local control handling preserves ANSI/ZWJ output and its word-bounded all-caps matching avoids the
Closing as superseded-and-merged. Thanks for covering the full emission surface — the checkpoint file was a gap nobody else had touched. |
Fixes #77484 — closes three verified secret-redaction gaps (all reproduced live on current main before fixing):
1.
_ENV_ASSIGN_REmisses*_KEY/*_PASS/*_PW+ lowercase env keysFAL_KEY=sk-abc123,OPENAI_KEY=sk-def456,MYSQL_PASS=ghi789,DB_PW=jkl012, and lowercaseopenai_key=sk-def456all leaked verbatim throughredact_sensitive_text, whileMY_API_KEY/GITHUB_TOKENmasked correctly._SECRET_ENV_NAMESgains bareKEY/PASS/_?PWalternatives._SECRET_CFG_NAMES(line-anchored + dotted config passes) gainskey/pass/pw, so lowercase .env keys likeopenai_key=mask without touching mid-string prose or URLs._KEY_KEYWORD_RE(word-boundary gate) gains barekey/pass/pwsoopenai_key/mysql_passpass validation whilemonkey/keyboard/passage/secretarystay untouched.2. Control-char token splitting
sk-abc123\x1bsk-def456,sk-abc123\u200bsk-def456, and CR-split tokens passed every regex unmasked.redact_sensitive_textnow strips C0 controls (except\n/\t) + zero-width/format chars before matching, and normalizes\r→\n.\n/\tare preserved (they carry line structure; the line-anchored_CFG_*_REpasses depend on it).3.
process(action=list)unredactedtools/process_registry.pyreturned rawlist_sessions(...)JSON (rawcommand[:200]+output_preview[-200:]with inline secrets), unlike poll/log/wait/kill which are wrapped in_redact_process_result. Added_redact_process_listmapping the existing redactor over each entry.Tests
tests/agent/test_redact.py: env-name gap (bare suffixes, lowercase, prose-not-mangled), control-char splits (ESC/zero-width/CR, newline-structure preserved).tests/tools/test_process_registry.py:process(action=list)redacts command + output_preview.test_redact.py80/80,test_process_registry.py55/55, redaction-adjacent suites 62/62, ruff clean.Also fixes #55319 and #55321 (mask_secret() no longer emits control bytes in the visible mask head/tail — the prior PR #58079 was closed without merging).