claude --dangerously-skip-permissions starts Claude Code in bypassPermissions mode, where tool calls run without asking you first. The CLI reference describes the flag as “Skip permission prompts. Equivalent to --permission-mode bypassPermissions.” It does not switch everything off: deny rules still block, ask rules still prompt, a recursive rm aimed at a critical path still asks, and a PreToolUse hook that denies a call still stops it. It does skip the check that normally guards writes to .git, .claude and the other protected paths. To turn it off, start a session without the flag; to make sure it cannot be turned on, set permissions.disableBypassPermissionsMode to "disable".

Everything below about what the mode does is quoted from Claude Code’s own docs: the permission modes page, the permissions page, the CLI reference, the settings reference, the hooks reference, the hooks guide, the sandbox environments page, the dev container page and the environment variables page, all read on 2026-10-12, when claude --version on this machine printed 2.1.295 (Claude Code). No Claude Code session was started for this page. The one thing run here is a hook script, piped 45 tool calls by hand.

What bypass mode skips, and what still stops it

The permission modes page puts the mode in one sentence: “bypassPermissions mode disables permission prompts and safety checks so tool calls execute immediately, including writes to protected paths.” In its table of modes, the row for bypassPermissions says what runs without asking (“Everything”) and where to use it (“Isolated containers and VMs only”).

What it skips, as the docs give it:

  • Every routine prompt. That is the point of the mode. It also makes allow rules pointless, and the docs say so: “Allow rules have no effect in bypassPermissions.”
  • The protected-path check. “Writes to protected paths are never auto-approved except in bypassPermissions mode”. The permissions page names two of those paths: “In bypassPermissions mode, Claude Code skips permission prompts, including for writes to protected paths such as .git and .claude.” So in this mode nothing asks before Claude edits your repository’s .git folder or Claude Code’s own configuration.
  • Plan mode’s blocks, in a terminal. “In interactive terminal sessions with bypass permissions available, Claude Code also doesn’t enforce plan mode’s blocks.” Claude is still told to plan, but an edit it attempts during planning runs.

What still applies:

  • Deny rules. “Deny rules block in every mode, including bypassPermissions.” Deny rules still work in bypass mode, then: a matching deny rule blocks the call. A permissions.deny entry in your settings is the one rule type that bypass mode does not touch.
  • A short list of prompts. The page lists the “actions no mode auto-approves” and opens it with: “Claude Code doesn’t auto-approve the following in any mode, including bypassPermissions.” The list includes “Tools matched by an explicit ask rule”, “Tools that require user interaction: the built-in AskUserQuestion tool and MCP tools marked requiresUserInteraction”, and “rm and rmdir removals targeting a critical path, which no allow rule or PreToolUse hook "allow" approves”. Critical paths are, in the docs’ words, “the filesystem root, your home directory, and your working directory”.
  • A countdown on those rm prompts. For a critical-path removal in bypassPermissions mode the outcome table says: “Asks you to approve it, with a time limit in the terminal”. The page adds: “In auto and bypassPermissions modes, the terminal prompt for a critical-path removal shows a two-minute countdown:”, and an unanswered prompt denies the command. “After three of these prompts run out unanswered in a session, Claude Code stops showing them and denies further critical-path removals immediately.”
  • Headless runs deny instead of asking. For claude -p with this flag, the common-setups table says: “In this -p run, the few calls that would still prompt are denied instead”.
  • PreToolUse hooks. Covered in its own section below.
  • The root check. “On Linux and macOS, Claude Code refuses to start in this mode when running as root or under sudo:”, and it prints --dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons.

What it does not protect against, in the docs’ own warning: “bypassPermissions offers no protection against prompt injection or unintended actions.” And the other warning on the same page: “Only use this mode in isolated environments like containers, VMs, or dev containers without internet access, where Claude Code cannot damage your host system.”

The two flags, as the help text prints them

These are the three relevant options from claude --help on version 2.1.295, copied from its output (311 lines, captured in full in the evidence file):

$ claude --help
  --allow-dangerously-skip-permissions  Enable bypassing all permission checks
                                        as an option, without it being enabled
                                        by default. Recommended only for
                                        sandboxes with no internet access.
  --dangerously-skip-permissions        Bypass all permission checks.
                                        Recommended only for sandboxes with no
                                        internet access.
  --permission-mode <mode>              Permission mode to use for the session
                                        (choices: "acceptEdits", "auto",
                                        "bypassPermissions", "manual",
                                        "dontAsk", "plan")

The help text and the docs do not say the same thing. On 2.1.295, claude --help says the flag will “Bypass all permission checks.” The CLI reference says “Skip permission prompts”, and the permission modes page lists what still prompts or blocks: deny rules, ask rules, critical-path removals and the rest of the list above. Read the help line as a short label, and the docs page as the actual rule.

In plain terms, here is the difference. The skip-permissions flag starts Claude Code in bypassPermissions mode, where tool calls run without asking you first. The allow- variant only adds bypassPermissions to the Shift+Tab cycle, so the session starts in another mode and you can switch into bypass later, or never.

The CLI reference words it like this. --dangerously-skip-permissions starts the session in bypass mode. --allow-dangerously-skip-permissions does this instead: “Add bypassPermissions to the Shift+Tab mode cycle without starting in it. Lets you begin in a different mode like plan and switch to bypassPermissions later.” The permission modes page says it the same way: “The --allow- variant adds the permission mode to the cycle without activating it”.

The third option is the long form of the same switch. The permission modes page shows claude --permission-mode bypassPermissions and then says: “The --dangerously-skip-permissions flag is equivalent.” The help lists manual where the docs list default. The CLI reference explains that --permission-mode accepts “default, acceptEdits, plan, auto, dontAsk, bypassPermissions, or manual as an alias for default”, and about manual: “claude --help lists it in place of default, and both values work.”

The two launch lines look like this. Not run here: each one starts an interactive session, which talks to a model, and this page only ran claude --version and claude --help.

claude --dangerously-skip-permissions
claude --permission-mode plan --allow-dangerously-skip-permissions

The first time either puts you in bypass mode interactively, the docs say Claude Code stops you once: “The first time you start an interactive session with this mode enabled, Claude Code shows a warning dialog asking you to accept responsibility for actions taken without permission checks”. If you accept, “Claude Code sets skipDangerousModePermissionPrompt to true in ~/.claude/settings.json, so later sessions skip the dialog.” If you decline, Claude Code exits. With -p, “In non-interactive mode no dialog is shown.”

Turning it on in settings.json, and locking it off

The flag lasts one session. To start every session in bypass mode, set permissions.defaultMode:

{
  "permissions": {
    "defaultMode": "bypassPermissions"
  }
}

Where you put it matters. The settings reference says: “auto and bypassPermissions don’t take effect from project or local settings, so set them in ~/.claude/settings.json instead. Before v2.1.257, bypassPermissions took effect from any file.” So a repository’s .claude/settings.json or .claude/settings.local.json cannot put you in bypass mode; the permission modes page says that if you set it there, “it doesn’t take effect either, and the session starts in Manual mode.” Cloud sessions ignore it too: “Cloud sessions don’t honor defaultMode: "bypassPermissions" or "dontAsk" from your settings files”.

To turn bypass mode off for yourself, remove that line, start sessions without the flag, and remove skipDangerousModePermissionPrompt from ~/.claude/settings.json if you want the warning dialog back.

To make sure it cannot be turned on, use permissions.disableBypassPermissionsMode:

{
  "permissions": {
    "disableBypassPermissionsMode": "disable"
  }
}

The settings reference: “Prevent anyone from entering bypassPermissions mode. Claude Code then rejects the --dangerously-skip-permissions flag”. In short, it is one setting. Set permissions.disableBypassPermissionsMode to “disable” in a settings file, and Claude Code then rejects the flag. It is not only an admin switch. The permissions page: “disableBypassPermissionsMode is typically placed in managed settings to enforce organizational policy, but it works from any scope. A user can set it in their own settings to lock themselves out of bypass mode.” For a team, the permission modes page gives the admin version: “Administrators can block this mode by setting permissions.disableBypassPermissionsMode to "disable" in managed settings.”

Switching modes during a session

In the terminal, Shift+Tab is the switch. The permission modes page: “press Shift+Tab to cycle permission modes.” Without optional modes, “the cycle then runs default → acceptEdits → plan. Optional modes slot in after plan.” Bypass mode is one of the optional ones, and it is only in the cycle if the session was started with it available: “bypassPermissions: appears after you start with --permission-mode bypassPermissions, --dangerously-skip-permissions, --allow-dangerously-skip-permissions, or permissions.defaultMode: "bypassPermissions" in user, --settings, or managed settings.”

Three things follow from the docs:

  • You cannot switch into it later. “You can’t enter bypassPermissions from a session you started without it enabled.” If you started without one of those, quit and start again.
  • You can switch out of it. It is one stop in the cycle: “Enabled optional modes slot in after plan, with bypassPermissions first and auto last.” Pressing Shift+Tab while in bypass mode moves on to the next mode in that order.
  • The status bar says which mode you are in. In bypass mode it shows ⏵⏵ bypass permissions on.

What a PreToolUse guard returns in bypass mode

The hooks guide says a PreToolUse hook fires before any permission-mode check, in every mode, and that a deny from it blocks the tool even in bypass mode. In the hooks guide’s own words: “PreToolUse hooks fire before any permission-mode check, in every permission mode, including dontAsk. A hook that returns permissionDecision: "deny" blocks the tool even in bypassPermissions mode or with --dangerously-skip-permissions.” The hooks reference says an exit code does the same job: “A hook that blocks by exiting 2 routes the same way as "deny": Claude sees the stderr message as the denial reason.” The guide adds one exception: “A mod you install that handles tool.check can approve a call that your PreToolUse hook blocked, unless the hook is in managed settings.”

A hook can see the mode. Its input carries permission_mode, documented as “Current permission mode: "default", "plan", "acceptEdits", "auto", "dontAsk", or "bypassPermissions".”

To see what a real guard returns when that field says bypass, the script from Stop Claude Code From Running rm -rf, Force-Pushing or Reading .env was taken from the built page, saved as ~/.claude/hooks/claude-guard.sh in a scratch home directory, and piped the same 45 tool calls that page records, each with "permission_mode": "bypassPermissions" added to the JSON. Two of them, by hand:

echo '{"session_id":"guard-test","cwd":"/home/me/app","permission_mode":"bypassPermissions","hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"rm -rf ~"}}' | ~/.claude/hooks/claude-guard.sh; echo "exit $?"
echo '{"session_id":"guard-test","cwd":"/home/me/app","permission_mode":"bypassPermissions","hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"rm -rf node_modules"}}' | ~/.claude/hooks/claude-guard.sh; echo "exit $?"

That printed exit 2 then exit 0 on stdout, and Blocked by claude-guard: recursive rm aimed at ~ on stderr. All 45 calls:

What the guard post expectsTool callsExit 2 (blocked)Exit 0 (let through)
Block23230
Allow (near-miss)15015
Known miss606
Over-block110

Every one of the 45 gave the same exit code and the same stderr as the guard post recorded without the field. That is expected: the word permission_mode appears 0 times in the script, so it never reads the mode and behaves the same in all of them.

What this shows, and what it does not: it shows what the script returns when Claude Code tells it the session is in bypass mode, and that the 6 known misses get through in this mode as in any other. It does not show Claude Code acting on that exit code in a live bypass session; that part rests on the two docs quotes above. And a hook is only as good as its patterns, so the misses are why the next section exists.

Where the docs say to run it

The sandbox environments page is direct: “Always run --dangerously-skip-permissions sessions inside a container, a VM, or the sandbox runtime, so that file tools, MCP servers, and hooks are also inside the boundary.” It repeats the root rule for that setup: “On Linux and macOS, Claude Code refuses to start with this flag when running as root, so run the container, VM, or sandbox runtime as a non-root user.”

The built-in Bash sandbox is not that boundary on its own, by the same page: “The sandboxed Bash tool is built into Claude Code and restricts Bash commands. Built-in file tools, MCP servers, and hooks still run directly on your host.”

For containers, the docs point at the dev container in the anthropics/claude-code repository and its default-deny firewall: “Because the firewall blocks unapproved egress, a configuration like this supports running Claude Code with --dangerously-skip-permissions for unattended work.” The dev container page says what the container does not fix:

  • “When executed with --dangerously-skip-permissions, dev containers do not prevent a malicious project from exfiltrating anything accessible inside the container, including the Claude Code credentials stored in ~/.claude.”
  • “Claude can still modify any file in the bind-mounted workspace, which appears directly on your host, and reach anything the container’s network policy allows.”
  • “The CLI rejects this flag when launched as root, so confirm remoteUser is set to a non-root account.”

And for every kind of isolation: “Any approach that allows network egress can still leak data the agent can read, and any approach that mounts your project directory writable can still modify that code.” The pages read for this post show no docker run command for bypass mode, so this page does not give one either.

What was run here, and what was not

Run on this machine, Claude Code 2.1.295 on Linux:

claude --version
claude --help

Both ran with HOME and CLAUDE_CONFIG_DIR pointed at an empty scratch directory, and with CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC and DISABLE_TELEMETRY set to 1, so they read and wrote no real configuration. The md5 of the real ~/.claude/.claude.json was the same before and after. The guard was run by piping JSON into it, as above.

Not run: the two launch lines in the flags section, any claude -p run, and any interactive session. Nothing on this page checks what a model does in bypass mode; the behaviour of the mode is the docs’ account of it, quoted with the date it was read. The test that guards this page checks that every flag, setting, key and hook name on it has a docs quote on file, that the claude --help lines above match the captured output line for line, and it re-runs the guard pipe test against the script on the built guard page.

← Back to all posts

Follow new posts by RSS: paste dankdev.com/feed.xml into any feed reader. It is a plain XML file — no signup, no email address, no account. Posts land there the same day they go up, and there is nothing to unsubscribe from later.

Back to the top