Tool Stdout Is a Secret Envelope A developer warns that tool stdout is a secret envelope, arguing that command output, test logs, and stack traces can leak sensitive data to remote coding assistants. They propose a local redaction gate that filters high-risk patterns before any tool output is sent to a model, treating all tool results as untrusted data. The article includes a Python script as a proposed preflight filter and notes that MonkeyCode offers free model access and a free server option, with a disclosure that the piece is part of product outreach. When you wire a coding assistant to your shell, the dangerous payload is rarely the prompt you typed. Secrets ride out in command output, test logs, and stack traces that tools dump without asking. You should treat every tool result as untrusted data that must cross a redaction gate before it reaches a remote model. That gate is a local program you control, not a hopeful instruction buried in a system prompt. Picture the coding assistant as a contractor who stands just outside your office glass all afternoon. You can hand papers through a slot, yet you cannot unsay anything once the page leaves the room. Remote inference works the same way, because the model and any request store sit beyond your process boundary. A free server does not change that geometry; it only makes the slot easier to use during ordinary weekday work. The threat model stays small if you draw it on one page and refuse to romanticize agents. Your laptop still holds secrets, customer fixtures, and deployment wiring that must never travel with a prompt. The remote model is an untrusted peer that may train on nothing and still keep logs you never see. Between those two rooms sits the agent loop, which will happily cat a file because a stack trace named its path. You already know not to paste a production env file into a chat box like a tourist. The quieter failure is docker compose config , kubectl describe , env , and a failing test that prints a signed URL. Those commands are useful, so you run them, and the tool layer forwards the stdout as if it were just another comment. The model then helps by quoting the secret back, which copies it into yet another persisted log line. If you practice this workflow against a remote coding assistant, keep the product in its place as a convenience, not as a vault. MonkeyCode offers free model access and a free server option that can host that loop while you iterate on local gates. Disclosure: This article was prepared as part of MonkeyCode's product outreach, stated here before any workflow advice continues. The disclosure does not change the boundary, because the server still sits outside your laptop, so redaction stays local. Draw four boundaries even if your diagram looks boring on a whiteboard in a quiet hallway. One boundary is the agent process versus the files it can open without extra confirmation from you. Another is the network cable, where a completion request leaves and you lose practical recall of the bytes. Persistence and people complete the map, because transcripts and operators may outlive the debugging session you meant to keep brief. Secrets are not only API keys sitting in a file named env, though that file remains a classic mistake. They also hide in PEM blocks, bearer headers, database URLs, session cookies, and cloud credential process exports. Customer fixtures can be worse, because a unique email in a failing test can identify a real person. You should assume any string that grants access or names a private person is ineligible for the model. Hope is not a control, so you want a local gate that fails closed when it sees a high risk pattern. The script below is a proposed filter you run on your machine before any tool stdout is attached to a request. It refuses known credential shapes and sensitive path names, then writes a sanitized bundle or exits with an error. Treat it as a seatbelt rather than a vault door, because regular expressions miss encodings and novel token formats. bash /usr/bin/env python3 """Proposed local preflight gate for assistant context. Run this on your machine.""" from future import annotations import argparse import re import sys from pathlib import Path DENY NAME PARTS = '.env', 'id rsa', 'id ed25519', 'credentials', 'kubeconfig', 'serviceaccount', '.pem', '.p12', 'terraform.tfstate', PATTERNS = 'aws access key', re.compile r'AKIA 0-9A-Z {16}' , 'pem block', re.compile r'-----BEGIN ?:RSA |EC |OPENSSH ?PRIVATE KEY-----' , 'bearer', re.compile r' ?i bearer\s+ A-Za-z0-9. \- += ' , 'jwt', re.compile r'eyJ A-Za-z0-9 - {8,}\. A-Za-z0-9 - {8,}\. A-Za-z0-9 - {8,}' , 'db url', re.compile r' ?i ?:postgres|mysql|mongodb|redis :// ^\s +' , 'generic secret assign', re.compile r' ?i api - ?key|secret|password|token \s := \s \S+' , PLACEHOLDER = ' REDACTED:{label} ' def path denied path: Path - str | None: lowered = str path .lower for part in DENY NAME PARTS: if part in lowered: return part return None def scan text text: str - list str : hits = for label, cre in PATTERNS: if cre.search text : hits.append label return hits def redact text text: str - str: out = text for label, cre in PATTERNS: out = cre.sub PLACEHOLDER.format label=label , out return out def main - int: parser = argparse.ArgumentParser description='Fail closed on secret-shaped context.' parser.add argument 'paths', nargs=' ', type=Path parser.add argument '--stdin', action='store true' parser.add argument '--redact', action='store true', help='Print redacted text instead of refusing.' parser.add argument '--max-bytes', type=int, default=200000 args = parser.parse args chunks: list tuple str, str = if args.stdin or not args.paths: data = sys.stdin.read args.max bytes + 1 if len data args.max bytes: print 'gate: stdin exceeds max-bytes', file=sys.stderr return 2 chunks.append '