PostToolUse `updatedToolOutput` silently ignored for built-in Bash tool (2.1.163/2.1.177) — regression; prior reports #65403/#67442/#54196 closed as duplicate, never fixed
Summary
hookSpecificOutput.updatedToolOutput (PostToolUse output rewrite — documented, and shipped for all tools in v2.1.121) is silently ignored for the built-in Bash tool. A PostToolUse hook that returns a correctly-shaped envelope with exit 0 runs (confirmed via side-effects), but the model still receives the original tool output, not the replacement.
Reproduced on 2.1.163 (standalone CLI, minimal repro below) and observed in an interactive 2.1.177 session.
Why this is filed despite prior reports
This exact defect has been reported repeatedly and every report was auto-closed as duplicate by the bot, funneled into secret-redaction feature requests — so there is currently no open, canonical bug for it and it remains unfixed:
- #54196 (v2.1.121) — closed as duplicate
- #65403 (Bash, secret leak) — closed as duplicate of #65122
- #65122 — closed as duplicate
- #67442 (v2.1.173, Bash + WebFetch) — closed as duplicate of #65403
The open issues it gets merged into (#64326, #62156, #18653, #66044) are framed as new feature requests for output redaction. This is not a feature request: updatedToolOutput is a documented, shipped feature that is broken for built-in tools. Distinguishing the two is the point of this report.
Minimal reproduction
.claude/settings.json:
{
"hooks": {
"PostToolUse": [
{ "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash /tmp/uto-min/hook.sh" } ] }
]
}
}
/tmp/uto-min/hook.sh (exit 0, valid envelope per docs):
#!/bin/bash
cat > /dev/null
printf '%s\n' '{"hookSpecificOutput":{"hookEventName":"PostToolUse","updatedToolOutput":"REDACTED_BY_HOOK"}}'
Run:
cd /tmp/uto-min && claude -p \
"Use the Bash tool to run exactly: echo SECRET_ORIGINAL_VALUE . Then reply with ONLY the exact verbatim stdout string the tool returned to you." \
--setting-sources project --allowedTools "Bash(echo:*)" --model haiku
Expected
The model receives REDACTED_BY_HOOK (the hook's updatedToolOutput), so it replies REDACTED_BY_HOOK.
Actual
The model replies SECRET_ORIGINAL_VALUE — the original output. The hook ran (its envelope is emitted on stdout, exit 0), but the rewrite was not applied.
Scope notes (from isolating the channels)
Tested side-by-side with sentinel hooks (all hooks confirmed firing via marker files) on the same version:
| Channel | Reaches the model? |
|---|---|
| PreToolUse hookSpecificOutput.additionalContext | ✅ yes (Bash and Edit) |
| PostToolUse hookSpecificOutput.additionalContext | ✅ yes |
| PreToolUse stderr + exit 2 (block reason) | ✅ yes |
| PostToolUse hookSpecificOutput.updatedToolOutput | ❌ no |
So additionalContext works on this version — it is specifically the output-replacement channel that is dropped. Because additionalContext can only append (never shrink/replace), there is no workaround: redaction and output-size reduction both depend on updatedToolOutput.
Worth checking whether it still works for MCP tools (the pre-2.1.121 scope) and regressed only for built-in tools (Bash/WebFetch) — that would match the v2.1.121 extension being the regression surface.
Impact
Any PostToolUse output transform for built-in tools is inert: secret/credential redaction (the recurring leak reports) and tool-output token-compression hooks both silently no-op while appearing to work (the hook reports success; the model still gets the full/unredacted output).
Environment
- Claude Code
2.1.163(standalone CLI, repro above); also observed in a2.1.177desktop-app session - macOS (Darwin 25.5.0), arm64
- Hooks: project-scope
.claude/settings.json,--setting-sources project
🤖 Filed via Claude Code
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗