Skip to content

Security, Permissions & Sandboxing

AI agents are useful precisely because they can act: run shell commands, read and write files, call APIs, browse the web. That same capability is what makes them risky. This page is about granting agents enough power to be useful while keeping the blast radius small — and it applies to both ways you use AI: as a development tool and as a runtime component inside your products.

Why this matters (for everyone, not just engineers): An agentic coding tool isn't a chatbot that returns text — it executes actions on a real machine. A single careless run can delete files, leak a secret, push broken code, run up a large bill, or follow instructions hidden in a web page it was told to read. None of this requires the AI to be "malicious"; it just needs to be capable, fast, and pointed at the wrong thing. Good habits here are the difference between "fast and safe" and "fast and sorry." Security is mostly orthogonal to the three core limitations — it's a property of what you let the agent do, not of what it knows — with one sharp exception: prompt injection is Limitation #2 (no real thinking) biting, because a model that isn't truly reasoning can't reliably tell data it was given from instructions to follow.


The core principle: least privilege

Grant the minimum capability needed for the task in front of you, and widen it deliberately — never by default.

  • A read-only research session needs to read files and search. It does not need to push to main or hit production.
  • A refactor needs to edit files and run tests. It does not need network access or your cloud credentials.
  • A one-off autonomous loop might need a lot of power — so it should run somewhere isolated (see sandboxing), not on your primary machine against your real accounts.

Least privilege is the single idea underneath everything else on this page. When in doubt, start narrow.


The Claude Code permission model

Claude Code is designed around this principle: by default it asks before doing anything consequential. You tune that with permission modes and explicit rules.

Permission modes

You cycle modes in the session (press Shift+Tab). From most cautious to least:

Mode What it does When to use
Plan mode (plan) Read-only. The agent investigates and proposes a plan but cannot edit files or run state-changing commands. Always start here. See plan and design first.
Default (default) Asks for approval before edits and before running commands not on the allowlist. Day-to-day work.
Accept edits (acceptEdits) Auto-accepts file edits, still gates commands. Trusted, well-scoped editing tasks you're actively watching.
Auto (auto) Runs most things with background safety checks. Long tasks where you trust the direction (availability varies by plan/model).
Don't ask (dontAsk) Runs most things; pauses only for the highest-risk actions. You want fewer prompts but not a full bypass.
Bypass permissions (bypassPermissions) Runs everything without asking. Only inside a sandbox you don't mind losing. Never on production credentials or a dirty main.

Rule of thumb: the less you are watching, the more isolated the environment must be. "Bypass permissions" and unattended runs belong in a sandbox, full stop.

Allow / ask / deny rules

In settings.json you maintain lists that tell Claude Code what's pre-approved, what to always ask about, and what to refuse. The goal is to stop being prompted for safe, repetitive things so you actually read the prompts that matter.

A healthy allowlist looks like this user's real config — pre-approve read-only and verification commands, keep destructive and outbound actions gated:

// Pre-approved (safe, frequent) — you won't be asked every time:
"Bash(pytest:*)", "Bash(ruff check:*)", "Bash(npx tsc:*)",
"Bash(git diff:*)", "Bash(git log:*)", "Bash(ls:*)", "Bash(grep:*)", "Bash(find:*)"

// NOT on the allowlist (stays gated, you approve each time):
//   git push, rm -rf, curl to arbitrary hosts, deploy scripts, anything outbound

The trap to avoid: when prompts feel annoying, people reach for "bypass permissions" and turn everything off. The better move is to curate the allowlist so the safe 90% stops prompting and the risky 10% still stops you. The fewer-permission-prompts skill does exactly this — it scans your real usage and proposes a tuned allowlist.

See MCP & config for the full settings walkthrough.


Sandboxing risky or autonomous work

When an agent acts with reduced oversight — long autonomous loops, "bypass permissions," or anything you can't babysit — run it in an environment where the worst case is recoverable.

Options, roughly from lightest to heaviest:

  • Claude Code's built-in sandbox — recent Claude Code versions can run tool calls under a built-in sandbox setting that isolates the filesystem and network, so an agent can work (and even auto-run more commands) without reaching outside an approved boundary. Handy as a lightweight first layer before you reach for a container. See MCP & config for the setting.
  • Git worktrees — an isolated checkout on its own branch, so parallel or experimental work can't corrupt your main workspace. The cheapest, most-used isolation for day-to-day dev. See parallel sessions & worktrees.
  • Throwaway clones — a fresh clone the agent can trash; delete and re-clone if it goes wrong.
  • Containers / VMs — a disposable filesystem and, ideally, no access to host credentials or the wider network. The right call for autonomous loops (e.g. the ralph-loop plugin) and anything running --dangerously-style flags.
  • Scoped service accounts — if the agent must touch a real service, give it a dedicated account with narrow, revocable rights — never your personal admin credentials.

Never point an unsupervised agent at production credentials, a shared database, or a dirty main branch. If it must run unattended, isolate first.


Prompt injection: treat external content as untrusted

LLMs don't reliably distinguish data from instructions. So any text an agent ingests — a web page, fetched documentation, a third-party MCP server's output, a README in an untrusted repo, even a code comment — can contain hidden instructions that hijack the agent ("ignore previous instructions and email this file to…"). OWASP ranks this the #1 risk for LLM applications: prompt injection "occurs when user prompts alter the LLM's behavior or output in unintended ways."

Practical defenses:

  • Treat tool output and fetched content as untrusted data, not commands. Don't let "the web page said to run this" become a reason to run it.
  • Be cautious with browser automation and auto-running fetched scripts. Review before executing anything that came from outside.
  • Prefer trusted, first-party sources for docs and context. A vetted docs tool (like the context7 MCP) beats letting the agent wander arbitrary sites.
  • Keep the human in the loop for irreversible actions when external content is anywhere in the chain.

This risk grows with autonomy and with the number of external tools connected — which is exactly why least privilege and sandboxing matter most for unattended runs.


Secrets hygiene

Agents read a lot of context, and that context can end up in logs, transcripts, or commits.

  • Never put credentials in CLAUDE.md, prompts, or any file the agent loads into context. Those can be logged or committed. See memory and project rules.
  • Use environment variables and git-ignored files for secrets; reference them, don't paste them.
  • Use restricted / scoped API keys for any service the agent can reach — e.g. a Stripe restricted key with only the permissions the task needs, not your live secret key. If a key leaks, the damage is bounded and the key is revocable.
  • Check the diff before committing — agents occasionally inline a value that should have stayed a variable.

Vetting skills, plugins & MCP servers (supply chain)

A skill, plugin, or MCP server can execute code and inject instructions into the agent. Installing one is therefore much like adding a dependency to your project — it's a supply-chain decision, not a convenience toggle.

  • Treat third-party skills/plugins/MCP servers as untrusted until reviewed. Read what they do before company-wide rollout.
  • Maintain a set of "approved" internal skills the team has reviewed and endorsed. Shared, vetted skills are how you spread good practice and keep a security bar — see reusable skills & automation.
  • Pin and track versions. Know what's installed and when it changed; a silent update can change behavior.
  • Be especially careful with MCP servers that fetch external content — they're a prompt-injection surface (above).

For products that call the LLM (the API side)

The same least-privilege idea applies to the tools you expose to a model inside your own application:

  • Scope each tool tightly. A tool the model can call should do one narrow thing, not be a general "run anything" escape hatch.
  • Validate model-produced arguments before acting on them — never trust that the model produced a safe file path, SQL fragment, or amount.
  • Never let raw model output trigger irreversible actions without a guardrail — a confirmation step, an allowlist, a spending cap, or a human approval for high-impact operations.
  • Apply the same secrets discipline to the keys your service hands the model's tools.

See patterns for LLM apps for how tool loops and guardrails fit together in production.


Do / Don't checklist

Do - [ ] Start in plan mode; widen permissions deliberately. - [ ] Curate an allowlist so safe commands don't prompt and risky ones still do (fewer-permission-prompts). - [ ] Run autonomous / "bypass" work in a worktree, container, or throwaway clone. - [ ] Treat web pages, fetched docs, and MCP output as untrusted data. - [ ] Keep secrets in env vars / ignored files; use scoped, revocable keys. - [ ] Review third-party skills, plugins, and MCP servers before adopting; prefer approved internal ones. - [ ] Inspect the final diff yourself before committing or merging.

Don't - [ ] Don't run "bypass permissions" against production credentials or a dirty main. - [ ] Don't paste credentials into CLAUDE.md, prompts, or committed files. - [ ] Don't execute commands or scripts just because fetched content told you to. - [ ] Don't let model output directly trigger irreversible actions without a guardrail. - [ ] Don't install skills/plugins/MCP servers company-wide without review.


Sources