Skip to content

fix: prevent secret placeholder writeback on file read/write tools (#1333)#1343

Merged
Aaronontheweb merged 2 commits into
netclaw-dev:devfrom
Aaronontheweb:worktree-fix-1333-secret-redact-writeback
Jun 6, 2026
Merged

fix: prevent secret placeholder writeback on file read/write tools (#1333)#1343
Aaronontheweb merged 2 commits into
netclaw-dev:devfrom
Aaronontheweb:worktree-fix-1333-secret-redact-writeback

Conversation

@Aaronontheweb
Copy link
Copy Markdown
Collaborator

Summary

SecretOutputRedactor was replacing real secret values with ***REDACTED*** in file_read output before it reached the model. When the model wrote that content back via file_write/file_edit, the placeholders got persisted to disk, destroying real secrets in config files like appsettings.json (#1333).

The fix: redaction belongs on the observability path (spill files, session logs), not on the model-facing tool result. FileReadTool now opts out of model-facing redaction via a new INetclawTool.SuppressOutputRedaction flag while the dispatcher still writes redacted content to spill files on disk.

Separately, this consolidates file_write into FileEditTool as a Content parameter mode. FileWriteTool stays registered under the file_write tool name but delegates to FileEditTool.WriteFileAsync.

Changes

INetclawTool.SuppressOutputRedaction (default false) tells DispatchingToolExecutor to skip SecretOutputRedactor on the result sent back to the model. FileReadTool sets it to true. The dispatcher computes both raw and redacted versions: raw goes to the model, redacted goes to ToolOutputSpill for the on-disk spill file. Streaming ToolActivityUpdate chunks always redact regardless of the flag since they're progressive display, not content the model writes back.

FileEditTool.Params picks up an optional Content parameter for full-file writes, mutually exclusive with OldString/NewString/ReplaceAll. The write logic lives in FileEditTool.WriteFileAsync (internal), and FileWriteTool delegates there so existing sessions, approval grants, and audience profiles keep working under the file_write name.

SessionLogActor now redacts ToolResultOutput.Result before writing to session.log, closing a leak where SuppressOutputRedaction would have put raw secrets into the observability log. Updated ToolOutputSpill doc comments to match the two-param overload.

Test plan

  • File_read_preserves_secret_values_for_model - reads file with secrets, verifies model result is unredacted
  • Shell_output_still_redacts_secrets - verifies shell_execute output is still redacted
  • File_read_spill_file_is_redacted_even_when_model_result_is_not - forces spill, verifies model sees raw content but spill file on disk is redacted
  • Content_creates_new_file, Content_overwrites_existing_file, Content_creates_parent_directories - FileEditTool Content mode
  • Content_and_OldString_are_mutually_exclusive, Content_and_NewString_are_mutually_exclusive, Content_and_ReplaceAll_are_mutually_exclusive - validation
  • Full test suite: 2,203 Actors + 409 Config tests pass

@Aaronontheweb Aaronontheweb added bug Something isn't working observability security Security-related changes tools Issues related to agent tools: file_read, web_search, shell_execute, image processing, etc. labels Jun 6, 2026
…older writeback (netclaw-dev#1333)

SecretOutputRedactor was replacing secret values with ***REDACTED***
placeholders in file_read output before it reached the model. When the
model subsequently wrote that content back via file_write/file_edit, the
placeholders were persisted to disk, destroying real secret values in
config files.

The fix moves redaction out of the model-facing path for file tools while
keeping it on the observability path (spill files, logs, transcripts):

- Add SuppressOutputRedaction flag to INetclawTool; FileReadTool opts in
- DispatchingToolExecutor splits model-facing (raw) vs spill (redacted)
  result when the flag is set
- ToolOutputSpill gains a two-param overload so spill files always use
  redacted content even when the inline result is unredacted
- Consolidate file_write logic into FileEditTool as a Content parameter
  mode; FileWriteTool becomes a thin backward-compatible delegate
- Redact tool results in SessionLogActor before writing to session.log
  so file_read's SuppressOutputRedaction doesn't leak secrets to the
  observability log on disk
- Tighten FileEditTool Content mutual-exclusivity guard to also reject
  NewString and ReplaceAll (not just OldString) when Content is supplied
- Always redact streaming ToolActivityUpdate chunks regardless of
  SuppressOutputRedaction — activity chunks are progressive display, not
  content the model writes back
- Fix stale doc comment in ToolOutputSpill that claimed inputs are
  always pre-redacted
- Normalize error message casing in FileWriteTool ('path' → 'Path')
@Aaronontheweb Aaronontheweb force-pushed the worktree-fix-1333-secret-redact-writeback branch from 69911aa to 02f6737 Compare June 6, 2026 21:55
@Aaronontheweb Aaronontheweb merged commit 8b62cd5 into netclaw-dev:dev Jun 6, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working observability security Security-related changes tools Issues related to agent tools: file_read, web_search, shell_execute, image processing, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant