fix(agent): restrict secret redaction to credential fields to stop corrupting code output (#33801) - #39001
fix(agent): restrict secret redaction to credential fields to stop corrupting code output (#33801)#39001rodboev wants to merge 2 commits into
Conversation
…rrupting code output (NousResearch#33801)
|
This PR is a great step forward, but it leaves one redaction class untouched that has an outsized impact: The problem is that Actual bytes on disk (correct): return f"postgresql://{auth}@{self.pg_host}:{self.pg_port}/{self.pg_database}"The consequence is a hallucination feedback loop: the agent writes correctly, reads back via This bit a Kanban worker today — two consecutive 90-iteration timeouts on a task that needed to write a pydantic-settings
Only literal |
|
Good catch — I hadn't considered that |
|
Thanks for this — the diagnosis was on the right track and the test suite was thorough. We landed a root-cause fix for #33801 in #54061 (merged: 674e16e). One thing your fix didn't catch, which is why we went a different route: the The merged fix forbids whitespace in the userinfo/password groups ( |
Summary
The regex-based secret redactor (
agent/redact.py:redact_sensitive_text()) runs over the full text of tool output fromexecute_code,terminal, andwrite_file, corrupting code syntax when patterns likeMAX_TOKENS=100,"apiKey": "test", or${{ secrets.DEPLOY_TOKEN }}match the ENV-assignment, JSON-field, or prefix regexes. Users report spending 30+ minutes per session working around the corruption, andexecute_codeis effectively unusable for tasks involving credentialed API calls.The function already has a
code_file=Trueparameter that skips the ENV-assignment (_ENV_ASSIGN_RE) and JSON-field (_JSON_FIELD_RE) regexes, andfile_tools.pyalready passes it. Theterminalandexecute_codetools do not, so both get false-positive redaction on code output. A second false-positive class (documented in the issue thread by @yzzztech) comes from_PREFIX_REmatching credential-shaped prefixes inside GitHub Actions template references (${{ secrets.* }},${{ vars.* }}), shell variable references ($VARNAME,${VARNAME}), and similar template syntax. These are variable references, not bare credentials, and redacting them breaks CI/CD workflow files.This PR adds
code_file=Trueto all fourredact_sensitive_text()calls incode_execution_tool.py(3 calls) andterminal_tool.py(1 call), matching the approach in open PR #33840. It goes further by making_PREFIX_REtemplate-context-aware whencode_file=True: matches inside${{ ... }},${...}, or$VARNAMEcontexts are preserved. Bare credential-shaped strings (e.g. a literalsk-proj-...token in output) are still redacted. Auth headers, private keys, DB connection strings, JWTs, and Telegram tokens are unaffected bycode_file=Trueand continue to be redacted in all tool output.Fixes #33801
Changes
tools/code_execution_tool.py: passcode_file=Trueto all 3redact_sensitive_text()calls (lines 1028, 1429, 1430)tools/terminal_tool.py: passcode_file=Trueto theredact_sensitive_text()call (line 2338)agent/redact.py: add_preserve_template_prefix()helper and_TEMPLATE_CONTEXT_REregex; whencode_file=True,_PREFIX_REmatches inside template variable references are preserved instead of masked (+~15 lines)tests/agent/test_redact.py: addTestCodeFileParameterclass with 9 tests covering ENV skip, JSON skip, bare prefix still redacted, GitHub Actions template preserved (using realsk-prefix inside${{ }}), shell variable preserved (using realghp_prefix inside${}), trailing credential after template still redacted, auth header still redacted, JWT still redacted, private key still redacted (+~55 lines)tests/tools/test_terminal_output_transform_hook.py: addtest_terminal_output_code_file_skips_env_assignmentconfirming the terminal tool passescode_file=True(+~15 lines)Validation
MAX_TOKENS=100in execute_code outputMAX_TOKENS=***MAX_TOKENS=100"apiKey": "test"in terminal output"apiKey": "***""apiKey": "test"${{ secrets.DEPLOY_TOKEN }}in write_file/terminalghp_etc.sk-proj-abc123...in terminal outputAuthorization: Bearer <token>in code outputeyJhbG...) in execute_code stderrread_fileoutput (file_tools.py)code_file=Truecode_file=TrueTest plan
pytest tests/agent/test_redact.py -v --timeout=0— 83 passedpytest tests/tools/test_terminal_output_transform_hook.py -v --timeout=0— 10 passedTestCodeFileParameter(9 tests) covering allcode_file=Truebehaviors including template-context preservation with real prefix patternstest_terminal_output_code_file_skips_env_assignmentconfirming terminal integrationtest_terminal_output_transform_still_runs_strip_and_redactconfirms prefix redaction on bare secretsNot in scope
Moving redaction to a display-only layer (the suggestion in the issue body and PR #16849's
display_redaction_onlyconfig key) is deliberately left out. That is a larger architectural change that would require auditing every call site where tool output enters the model context. Thecode_file=Trueapproach is narrowly scoped, backward-compatible, and addresses the reported corruption without changing the redaction architecture. The_PREFIX_REtemplate-context fix is also conservative: it preserves matches only inside recognized template syntaxes, not all occurrences.