Is It Safe to Run AI Coding Agents With Permissions Off?
The approval prompts break your flow, the agent is mostly running npm test anyway, and there is a flag that makes them stop. So: is it actually safe to turn them off?
The short version:
- Stop the interruptions with the sandbox, not with a bypass flag. Auto-allow mode approves commands because a boundary contains them.
--dangerously-skip-permissionsapproves them because nothing is checking. - A sandbox is not all-or-nothing. Deny rules and scoped allow rules sit between “prompt for everything” and “prompt for nothing,” and they work when nobody is watching.
- The dial that bounds the damage is your credentials, and almost nothing written about this adjusts it.
- A git worktree is not a sandbox. It isolates working copies, not processes.
The honest answer to the headline question is that it is underspecified, because “permissions off” and “sandboxed” are two different dials that people treat as one. Skipping permission checks on a laptop holding your production credentials is a different proposition from working inside a tight boundary — and it is the configuration a “just use YOLO mode” recommendation usually leaves you in.
This guide separates the dials, covers what each agent enforces today, and looks at what changes when several agents run unattended at once — where the answer shifts most.
A git worktree is not a sandbox
Start here, because it is the misconception that matters most in parallel workflows, and one our own product could easily be misread as solving.
Giving every agent its own git worktree isolates working copies. Two agents cannot overwrite each other’s files, and each produces a reviewable branch. That is a correctness boundary, and a good one.
It is not a security boundary. Every one of those agent processes still has:
- the same filesystem, including
~/.ssh/,~/.aws/credentials, and every other project on the machine - the same network access
- the same environment variables, including anything exported in your shell profile
- the same shared Git state — linked worktrees share the repository’s object store and most refs
Anthropic’s own sandbox documentation makes the last point concrete: when the working directory is a linked worktree, the sandbox deliberately allows writes to the main repository’s shared .git directory, so that git commit works at all. Writes to hooks/ and config inside it stay denied — which is precisely the acknowledgement that a shared .git is a place where one worktree can affect another.
Worktrees answer “can these agents corrupt each other’s edits?” They do not answer “what can this process reach?”
Three dials, not one
| Dial | Controls | What removing it costs you |
|---|---|---|
| Approval prompts | Whether an action runs at all | The human check before each action |
| Sandbox | What a running process can touch | OS-level enforcement of filesystem and network limits |
| Credential reach | What is within reach if something is touched | The blast radius when the first two fail |
These are largely independent. You can have prompts on and no sandbox, which is the default in several tools and feels safe while offering no enforcement once you approve something. You can have a tight sandbox that approves commands automatically because it contains them, which is what makes low-interruption work reasonable. And the dial that most advice leaves alone is the third one, even though it is the only one that limits how bad the worst case gets.
The distinction that makes this concrete: permission prompts are evaluated before a command runs, based on the command string. The sandbox is enforced by the operating system on the running process — so it holds even when an approved command turns out to do more than its name suggested.
What each agent gives you today
Agent defaults change frequently, so treat this as orientation and check your version’s documentation before relying on any specific behavior.
Claude Code: a capable sandbox with wide-open reads
Claude Code ships a sandboxed Bash tool that uses Seatbelt on macOS and bubblewrap on Linux and WSL2. Native Windows is not supported; run it under WSL2 there. /sandbox opens the configuration panel.
Defaults worth knowing:
- Writes are limited to the working directory and its subdirectories, anything added with
--add-dir, and the session temp directory. - Reads cover the entire computer except explicitly denied paths. The documentation is direct that this “still allows reading credential files such as
~/.aws/credentialsand~/.ssh/.” Usesandbox.credentialsordenyReadentries to change that. - Network pre-allows no domains at all; the first connection to a new host prompts in Manual mode, or goes to the classifier in auto mode, and
allowedDomainspre-approves hosts.strictAllowlist(v2.1.219 and later) denies anything outside the list instead of prompting. - Environment variables are inherited by sandboxed commands, credentials included, unless you scrub them.
Two scope limits matter more than any of the settings. The sandbox covers Bash and its child processes — not every tool. Read, Edit, and Write “use the permission system directly rather than running through the sandbox,” and in-process tools such as WebFetch follow their permission rules rather than the sandbox’s domain allowlist. Turn prompts off and those tools are no longer bounded by either layer.
And the sandbox fails open by default. If it cannot start — a missing dependency on Linux, an unsupported platform — Claude Code warns and runs commands unsandboxed. sandbox.failIfUnavailable: true makes that a hard failure instead.
--dangerously-skip-permissions is not a sandbox setting. It replaces the per-action prompt with nothing and additionally skips protected-path checks. It is tempting to conclude that pairing it with a sandbox is therefore safe, and that conclusion is wrong for a specific documented reason: when a command fails under the sandbox, Claude Code may retry it with dangerouslyDisableSandbox, and “the retried command runs outside the sandbox, so it goes through the regular permission flow” — the flow that skipping permissions has removed. Setting "allowUnsandboxedCommands": false (shown as Strict sandbox mode in /sandbox) closes that path.
Anthropic’s permission-mode documentation scopes the mode explicitly to “isolated environments like containers, VMs, or dev containers without internet access.” Its documented recommendation for working locally with fewer prompts is different, and better: leave the permission mode at its default and switch the sandbox to auto-allow, so commands are approved because the sandbox boundary contains them rather than because nothing is checking.
Codex: the strictest defaults
Codex is sandboxed by default, with sandbox_mode taking three values:
| Value | Effect |
|---|---|
read-only | Inspect files; no edits or commands without approval |
workspace-write | Read, edit, and run commands inside the workspace. The default in trusted, version-controlled folders |
danger-full-access | No sandbox restrictions |
Two defaults are notably stricter than people expect. Network access is off in workspace-write — you opt in with network_access = true under [sandbox_workspace_write]. And within workspace-write, .git directories stay read-only, recursively, along with .agents and .codex if present. That is a meaningfully different stance from Claude Code’s, which opens the shared .git specifically so commits work; with Codex you approve the escalation instead — as long as approvals are still interactive. Under approval_policy = "never" there is nothing to approve and the command simply fails.
Approvals are a separate axis via approval_policy: untrusted, on-request, never, or a granular policy (on-failure still exists but is deprecated). The combined bypass is --dangerously-bypass-approvals-and-sandbox, aliased as --yolo, and it removes both layers at once.
Gemini CLI: sandboxing is opt-in
Sandboxing is opt-in rather than default: set GEMINI_SANDBOX to true, docker, podman, sandbox-exec (macOS), runsc, or lxc, or pass the sandbox flag. Read the default macOS profile carefully before relying on it — permissive-open confines writes to the project directory but still allows broad file reads and network access. --approval-mode=yolo auto-approves tool calls, and the older --yolo flag is deprecated in favor of it; running either without also enabling the sandbox is the configuration to avoid.
The middle ground everyone skips
The debate is usually framed as prompt-for-everything versus prompt-for-nothing, which ignores the setting that actually fits unattended work: rules that decide without asking.
Permission rules are evaluated before a tool runs, exactly like a prompt, but they resolve from a list instead of from a human. That makes them the one part of the permission layer that keeps working when nobody is watching — which is precisely the tier-3 situation. A deny rule holds at 3am; a prompt does not.
For Claude Code these live in settings.json alongside the sandbox keys:
{
"permissions": {
"deny": ["Bash(git push:*)", "Read(./.env)", "Read(./secrets/**)"],
"allow": ["Bash(npm test:*)", "Bash(npm run lint)"]
},
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"network": { "allowedDomains": ["registry.npmjs.org", "github.com"] }
}
}
The Codex equivalent lives in config.toml:
sandbox_mode = "workspace-write"
approval_policy = "on-request"
[sandbox_workspace_write]
network_access = false
Deny rules are worth more than allow rules here. An allowlist has to anticipate every safe command and gets widened whenever it blocks something; a short denylist of the operations you never want taken unattended — pushing, deploying, reading credential files, touching infrastructure state — costs little and does not erode. Note the deliberate github.com in that allowlist, though: it is exactly the broad entry Anthropic warns about below, and a repository-specific host is better where your setup allows one.
What “skip permissions” actually removes
The reason these flags feel harmless is that the failure they guard against is not the one people imagine. The concern is rarely that the model decides to do something malicious. It is that the agent is a confused deputy: a process holding your credentials, acting on text it did not write.
That text arrives from more places than the prompt:
- a dependency’s README or postinstall script the agent reads while debugging a build
- an issue or PR description you asked it to work from
- a web page fetched during research
- CI logs, error messages, test fixtures, code comments in a vendored directory
None of that is exotic; it is the normal working material of a coding task. Prompt injection in this setting does not need to be clever, because the agent already has the permissions — it only needs to suggest an action the agent was going to be allowed to take anyway.
This is also why the network dial matters more than it looks. Claude Code’s documentation warns that because its built-in proxy makes allow decisions from the client-supplied hostname without terminating TLS by default, broad entries like github.com “can create paths for data exfiltration,” including via domain fronting. An allowlist containing one popular domain is a much weaker control than an allowlist that is short and specific.
Two other escalation paths are worth naming because they are easy to enable by accident: allowing the Docker socket through a sandbox (/var/run/docker.sock) effectively grants host access, and granting writes to directories containing executables on your PATH, or to shell startup files, converts a sandboxed process into code execution elsewhere.
The parallel multiplier
Everything above applies to one agent. Running several at once changes the calculus in ways that are structural rather than incremental.
Nobody is watching. The entire point of running four agents is that you are not supervising any single one. Approval prompts were doing work you have now stopped doing, and the prompt-based model quietly stops functioning at concurrency — you approve to unblock, not to evaluate.
Approvals can outlive the task. A repository-scoped “don’t ask again” approval granted inside one worktree can apply to every checkout of that repository. The decision you made for a small task is inherited by every later one.
Shared resources are shared across worktrees. Ports, development databases, caches, test accounts, and provider rate limits sit outside the worktree boundary — the collision class covered in running multiple agents on one repo. Four agents running the same integration suite against one dev database will interfere with each other regardless of how well the filesystem is isolated — a coordination failure that looks like flaky tests.
Blast radius multiplies while attention divides. Four concurrent unattended processes with full credentials is a different risk posture than one, even though each is individually configured the same.
Subagents inherit the security boundary even when they get their own checkout. In Claude Code a subagent can be given isolation: worktree and a separate working copy, but it still runs in the parent’s process, under the parent’s sandbox, network allowlist, and credentials. Delegating adds concurrency and a correctness boundary; it does not add a security one — the guide to running multiple Claude Code agents covers that surface in detail.
A tiered policy
Security advice fails when it is uniform, because everything gets set to the loosest tier that any task needs. Three tiers, matched to what the work actually does:
| Tier | Work | What gates actions | Sandbox | Credentials |
|---|---|---|---|---|
| 1. Read-only | Research, code explanation, review, planning | Nothing needs to | Read-only mode | None needed |
| 2. Normal development | Editing code, running tests, in your checkout | Sandbox auto-allow, plus deny rules | On, workspace-scoped, network allowlisted | Development only |
| 3. Unattended or parallel | Several agents, long runs, nobody watching | Deny rules only — no human in the loop | Container or VM | Scoped, short-lived, no production access |
Tier 1 is the one to worry about least — an agent that cannot write or execute is genuinely low risk, and prompts there buy little.
Tier 2 is the daily default and the one worth configuring carefully once. Note what that column does not say: the way to stop being interrupted here is the sandbox’s auto-allow mode, not a flag that skips permission checks. Commands stop prompting because the boundary contains them. Add a network allowlist limited to the hosts your build actually needs, a denylist for the handful of operations you never want taken unattended, and credentials that only reach development systems.
Tier 3 is where the built-in sandboxes stop being sufficient on their own. Anthropic’s documentation states it plainly — “sandboxing reduces risk but is not a complete isolation boundary” — and is equally plain that the bypass modes belong in containers and VMs. OpenAI makes no equivalent blanket statement, but its guidance points the same direction, noting that even devcontainers “do not prevent every attack.” For genuinely unattended parallel work, the boundary you want is a container or VM with its own credentials, with the process-level sandbox as a second layer rather than the only one.
A hardening checklist
Ordered roughly by value per minute spent:
- Get production credentials off the machine. The single highest-leverage change, and it has nothing to do with agents. Nothing an agent does locally can reach production if the credentials are not there.
- Reach for the sandbox before you reach for a bypass flag. OS-level enforcement beats a prompt you have learned to dismiss — but get it from auto-allow mode, not from skipping permission checks.
- Close the fail-open and escape-hatch gaps.
sandbox.failIfUnavailable: trueso a sandbox that cannot start stops the session instead of silently running unsandboxed, andallowUnsandboxedCommands: falseso a blocked command cannot be retried outside the boundary. - Keep the network allowlist short and specific. Your package registry, your source host. Not “anything popular.”
- Scrub credentials from the subprocess environment. Claude Code exposes
sandbox.credentialsfor masking andCLAUDE_CODE_SUBPROCESS_ENV_SCRUBto strip credentials from all subprocesses. - Never allow the Docker socket through a sandbox, and be equally careful with writes to
PATHdirectories and shell startup files. - Put enforcement where the agent cannot reach it. Branch protection and required review hold regardless of what any local process decides. So do server-side deploy approvals. This is the layer that survives every other one failing.
- Use separate credentials per concurrent agent where the provider allows it, so an incident is attributable and revocable without stopping everything.
- Do not rely on
AGENTS.mdfor restrictions. Instruction files shape behavior and enforce nothing — see AGENTS.md and CLAUDE.md for what belongs where.
Anthropic’s guidance is worth repeating in general form: effective sandboxing needs both filesystem and network isolation, because either one alone can be used to undo the other. When you widen a default on one side, check what it opens on the other.
What this does not cover
A sandbox constrains what a process can reach. It says nothing about whether the code is any good.
An agent operating entirely within its permissions can still commit a subtle authorization bug, weaken a validation path, or add a dependency nobody vetted. That risk is unaffected by every setting in this article, and it scales with how much code lands per hour — which is precisely what parallel agents increase. The mitigation is review discipline — a consistent review checklist for AI-generated code and a deliberate integration process — not tighter permissions.
Where Parallel Code sits in this
Disclosure: Parallel Code is our product. It orchestrates agents; it does not replace their permission or sandbox settings.
Parallel Code launches each task in its own git worktree and branch, and runs the real agent CLIs rather than wrapping them. Two consequences follow directly.
First, each agent’s own permission and sandbox configuration is what applies. Your Claude Code settings, your Codex sandbox_mode, your GEMINI_SANDBOX value — the orchestrator does not override them, so configure them at the agent level.
Second, the worktree isolation is a correctness boundary, not a security one, exactly as described above. It is what makes each task independently reviewable and independently discardable. It is not what keeps a process away from your SSH keys. If you are running Tier 3 work, put the whole setup inside a container or VM.
Frequently asked questions
Is --dangerously-skip-permissions (YOLO mode) safe?
Less safe than pairing it with a sandbox makes it sound, because the two interact. When a command fails under the sandbox, Claude Code may retry it outside the sandbox, and that retry is resolved by the permission flow the flag has removed — so close it with allowUnsandboxedCommands: false if you use the flag at all. Anthropic scopes the mode to containers and VMs, and its documented way to work locally with fewer prompts is the sandbox’s auto-allow mode instead. On a laptop with cloud credentials in the environment and no sandbox, the flag removes the last check on a process acting on untrusted input.
Do git worktrees isolate agents from each other?
They isolate working copies, so concurrent agents cannot overwrite each other’s files, and each produces a separate reviewable branch. They do not isolate the filesystem, the network, environment variables, or credentials, and linked worktrees share the repository’s Git state. Use containers or VMs when you need an actual security boundary.
Which agent has the safest defaults?
Codex is the strictest out of the box: sandboxed by default in workspace-write, network access off unless enabled, and .git read-only within that mode. Claude Code’s sandbox is capable but its read defaults are broad — reads cover the whole machine, credential files included, until you restrict them. Gemini CLI’s sandbox is opt-in. Defaults change, so verify against your installed version.
Can prompt injection really affect a coding agent?
Yes, and it does not require anything exotic. Agents read dependency files, issue text, web pages, and logs as ordinary parts of a task. Anything in that material that suggests an action the agent is already permitted to take can be acted on. This is why network egress limits and credential scoping matter more than the number of prompts.
What should I change first?
Move production credentials off the development machine. It is the only item on the list that bounds the worst case regardless of which other layer fails, and it is unrelated to which agent you use.
Does running agents in parallel make any of this worse?
It changes the model rather than the magnitude. Approval prompts assume a human is evaluating each one, and at four concurrent agents you are approving to unblock rather than to judge. That is the point to move enforcement from prompts to the sandbox, the credential scope, and branch protection.
Pick the tier, then stop thinking about it
The reason this question keeps coming up is that it is usually asked as a binary — prompts on or off — when the useful decision is which tier of work you are doing and what boundary that tier needs.
Set up Tier 2 properly once: sandbox on, prompts off, short network allowlist, development-only credentials. Most days never leave it. When you move to genuinely unattended parallel runs, move the whole thing inside a container with its own credentials rather than loosening the flags. And keep the enforcement that does not depend on any local setting — branch protection, required review, server-side deploy approval — because that is the layer still standing when something upstream goes wrong.