The short version: the "run this command? [y/N]" prompt your coding agent shows you is a usability feature, not a security boundary. Its safety rests on two assumptions — that you're shown the real command, and that you'll read and judge it correctly every time. Both break. This month they broke technically, when Claude Code shipped a fix for a bug where a command could hide part of itself from the approval dialog. They break behaviourally every day, when an agent prompts you so often you hit "yes" on autopilot. The fix isn't a better prompt. It's layers underneath it: a sandbox, a deny-by-default network allowlist, and least-privilege credentials — in that order.

The prompt broke, and that's the point#

On August 6, Claude Code v2.1.223 fixed a Bash permission bypass where "a crafted command could hide parts of itself from permission checks" — commands padded with tabs or invisible Unicode could keep part of themselves out of the approval dialog (changelog). This is the most-scrutinized coding-agent CLI in the world, and its human-in-the-loop prompt — the entire basis of "you approve every command" — was spoofable.

The patch is good and you should take it. But the lesson is bigger than the bug: any security model whose last line of defense is "a human reads a string and clicks allow" inherits every weakness of that string's rendering and that human's attention. Spoof the render, or exhaust the attention, and the boundary is gone. You cannot patch your way out of a one-layer design. You have to add layers.

Layer 1 (load-bearing): a disposable sandbox#

The single most important move is to stop running the agent on the machine that matters. Give it a throwaway environment — a container, a fresh VM, a managed agent sandbox — whose filesystem and process space you can delete. Now the worst case of a bypassed prompt is a wrecked scratch environment, not your laptop, your SSH keys, or your production credentials.

The agent keeps full shell and read/write inside the box. The box is what's disposable. This is the layer that turns "the prompt got spoofed" from a breach into an annoyance.

Layer 2: deny-by-default network egress#

A contained command can still do damage if it can reach the internet: exfiltrate a secret, curl | sh a payload, POST your source to an attacker. So the sandbox's network should be deny-by-default with an allowlist of the handful of hosts the agent legitimately needs — your git host, your package registry, your model API — and nothing else.

This is also the layer that neuters prompt injection. An injected instruction can tell the agent to send data somewhere; an egress allowlist means somewhere doesn't resolve. Keep the allowlist tight: a broad github.com entry is still a plausible exfiltration channel.

Layer 3: least-privilege, short-lived credentials#

Assume the agent's environment leaks. Make the leak worthless.

Layer 4: the flag that undoes all of it#

There is one setting that collapses the whole stack: a blanket skip-permissions flag (--dangerously-skip-permissions and its cousins) pointed at input you don't control.

Auto-approving every action is genuinely fine on a scratch task in a throwaway container — it's why the flag exists. It becomes a foot-gun the instant the agent reads something an attacker can influence: a cloned repo's README, a fetched web page, a tool result. Now injected text can issue commands with no human in the loop and no prompt to spoof — because you turned the prompt off. Scope auto-approve to sandboxed, trusted-input tasks only. Everywhere else, keep the prompt on as one layer among several.

"Autonomous" and "unsupervised on untrusted input" are not the same setting. The first is the product. The second is the incident.

Layer 5: audit, so you can answer "what did it touch"#

None of the above prevents everything, so capture what the agent actually ran — shell history, session logs, tool-call records. After an incident (or a merely weird PR), the difference between "we know exactly what it executed" and "we're guessing" is whether you logged it. This is also where permission checks that fail closed and log their allow-rules earn their keep.

The minimum, for a team of one#

You don't need a security org. You need an afternoon:

  1. Run the agent in a container or managed sandbox — never straight on the host with your production keys.
  2. Give it a network allowlist of the few hosts it truly needs; deny the rest.
  3. Hand it scoped, short-lived tokens so a leak is low-value and self-expiring.

Then leave the approval prompt on — as your fourth layer, not your only one. The whole industry spent one week in August patching the permission layer of every major coding CLI (we tracked the patches here), and investors put $125M into an external agent-security layer the same week (Zenity). Both are telling you the same thing: the prompt was never the boundary. Build the boundary.