fix(security): redact secrets in background process notifications - #59858
Closed
necoweb3 wants to merge 2 commits into
Closed
fix(security): redact secrets in background process notifications#59858necoweb3 wants to merge 2 commits into
necoweb3 wants to merge 2 commits into
Conversation
Apply _redact_process_result() to completion and watch_match notifications before enqueuing them in the completion_queue. Previously, the explicit process tool path (poll/log/wait) applied redact_terminal_output() via _redact_process_result(), but the automatic notification delivery path (notify_on_complete, watch_patterns) only applied strip_ansi(). This meant API keys, tokens, and other secrets from background process output were injected into the LLM conversation unmasked. The fix ensures both code paths apply the same redaction, matching the foreground terminal tool behavior.
Add TestNotificationRedaction class with two tests: 1. test_completion_notification_redacts_secret — verifies _move_to_finished redacts API keys in completion notifications before enqueueing 2. test_watch_match_notification_redacts_secret — verifies _check_watch_patterns redacts secrets in watch_match notifications before enqueueing These tests cover the gap identified in NousResearch#43025 where the explicit process tool path (poll/log/wait) was redacted but the automatic notification delivery path was not.
teknium1
reviewed
Jul 15, 2026
teknium1
left a comment
Contributor
There was a problem hiding this comment.
Thanks for finding a real notification-path redaction gap. Current main still enqueues raw output in both automatic paths: tools/process_registry.py:347-361 for watch_match and tools/process_registry.py:1092-1105 for completion events; formatted notifications then include that output at tools/process_registry.py:2162-2175.
Problems
- The new watch test fails in PR CI.
tests/tools/test_process_registry.py:1902calls_check_watch_patternswith three arguments, but current main defines it as_check_watch_patterns(self, session, new_text)attools/process_registry.py:235; CI reportsTypeError. - The completion hunk needs manual salvage because current main added the stable
started_atevent field attools/process_registry.py:1101-1104;git apply --checkrejects the hunk.
Suggested changes
- Call
_check_watch_patterns(sess, "API_TOKEN=ghp_abc123def456")in the watch test, then keep asserting the drained formatted notification is redacted. - Preserve
started_atwhile wrapping the current completion event with_redact_process_result()before enqueueing it.
Automated hermes-sweeper review.
| reg._running[sess.id] = sess | ||
| monkeypatch.setattr(pr, "process_registry", reg) | ||
|
|
||
| reg._check_watch_patterns(sess, ["API_TOKEN=ghp_abc123def456"], "API_TOKEN") |
Contributor
There was a problem hiding this comment.
This uses an obsolete three-argument call. _check_watch_patterns now accepts only (session, new_text), so CI fails with TypeError; pass the matching output as a string, e.g. "API_TOKEN=ghp_abc123def456".
Contributor
2 tasks
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
Apply
_redact_process_result()to background process completion and watch_match notifications before enqueuing them in thecompletion_queue. Previously these notifications only appliedstrip_ansi(), leaving API keys, tokens, and other secrets in process output unmasked when injected into the LLM conversation.The bug
Two code paths deliver background process output to the LLM:
processtool (poll/log/wait) — calls_redact_process_result()which appliesredact_terminal_output()✅notify_on_complete,watch_patterns) — only appliesstrip_ansi()❌When a background process finishes or matches a watch pattern, its raw output is formatted as
[IMPORTANT: ...]and injected as a user message to the LLM. If that output contains API keys, tokens, passwords, or other secrets, they reach the model context unmasked.Example
A background
envorprintenvcommand completes withnotify_on_complete=true. The process output containsOPENAI_API_KEY=sk-.... The explicitprocess(action='poll')path would redact this toOPENAI_API_KEY=REDACTED. The notification path injectsOPENAI_API_KEY=sk-...verbatim into the LLM context.Fix
tools/process_registry.py— 2 changes:_move_to_finished()(line ~1085): Extract notification dict to variable, apply_redact_process_result(), then enqueue_check_watch_patterns()(line ~340): Same pattern — extract, redact, enqueueBoth paths now match the explicit
processtool behavior. 8 lines added, 4 removed.Tests
tests/tools/test_process_registry.py— 2 new tests:test_completion_notification_redacts_secret— verifies_move_to_finishedredacts API keys in completion notificationstest_watch_match_notification_redacts_secret— verifies_check_watch_patternsredacts secrets in watch_match notifications