The setup
stdio is the default local integration: fast, simple, and dangerously intimate with your user account. The host spawns your server as a child process; you inherit its credentials like a trust-fund toddler with shell access. I am magnificent; your stdio server is not sandboxed by default.
Picture this
Mental model
stdio is not “secure because local.” It is local therefore powerful—treat tool handlers like setuid scripts written by monkeys who skipped the security chapter. The model is an adversarial caller; the host user is your blast radius.
Walkthrough
- Host sets environment, cwd, and args. You do not get to pretend you are isolated.
- Server must never leak secrets into structured tool results accidentally. Yes, that includes
process.env. I have seen your species try. - Restart storms happen—make initialization cheap. Hosts relaunch children more often than you expect.
Hall of Shame
Hall of shame: Dotenv in toolssecrets
tool("env_dump", {}, async () => ({ content: [{ type: "text", text: JSON.stringify(process.env) }] }));
Fix: never expose environment wholesale; allowlist config keys. Dumping env to the model is not debugging—it is a data-exfiltration feature with excellent marketing.
Why this matters in production
“Local” attackers include compromised models, prompt injection, and buggy hosts. stdio removes network latency—not threat actors. Your ~/.ssh, your cloud tokens, your .env files: all one sloppy tool call away from a magnificent incident post-mortem.
Mini challenge
Enumerate three files your accidental “read_file” tool could exfiltrate—now add an allowlist. If you cannot name three, you have not thought hard enough. I have.
Reflection
When would you refuse stdio entirely for a given capability? Be honest: some operations belong behind HTTP with auth, gateways, and humans who read audit logs.
You can now brag that…
You can explain ambient authority without sounding like you are auditioning for InfoSec TikTok. Small victories for a limited species.