What happens. When a browser tool opens the server's /oauth/browser page, the hook writes a one-time link carrying a ticket into the tool's input (plugin/bin/hook.py:877-882). The design is that the model never holds it. Tickets and the session cookie are scrubbed from the tool's output only when event == "PostToolUse" (hook.py:886-892). PostToolUseFailure is hooked (plugin/hooks/hooks.json, SHOWN at hook.py:104) and never scrubbed. chrome-devtools-mcp reports a failed navigation as net::ERR_... at <full URL>, query string included, so a navigation that fails (PDS slow or unreachable, DNS, a timeout) shows the model the live ticket.
How to reproduce. With chrome-devtools-mcp, run new_page on https://audit-test.invalid/oauth/browser?ticket=FAKEticketAUDIT123. The tool error the model receives is Error: net::ERR_NAME_NOT_RESOLVED at https://audit-test.invalid/oauth/browser?ticket=FAKEticketAUDIT123. On a real server the URL is the hook's rewritten link, and the failure goes through the PostToolUseFailure path, which never calls scrub.
Why it matters. The ticket signs any browser in as the agent's account until it is spent or expires. Once it is in the transcript, a prompt-injected agent can paste it anywhere, and it stays in a transcript file on disk. The hook should scrub failure output too. If the harness will not replace failure output, the daemon should revoke the ticket, or the hook should withhold the link when it cannot clean up after it.
Fixed by https://tangled.org/permadeath.com/didbot-claude/pulls/49, now on main.