Interactive permission mode toggle persists permissions.defaultMode to settings.json

Resolved 💬 1 comment Opened May 9, 2026 by Go-Jinhan Closed Jun 7, 2026

Summary

Toggling the permission mode to "Bypass Permissions" during an interactive session
(via Shift+Tab) writes permissions.defaultMode: "bypassPermissions" into the
user's ~/.claude/settings.json and leaves it there. The next session then
starts in bypass mode by default, which is a dangerous and surprising default
for what was meant to be a session-scoped toggle.

Steps to reproduce

  1. Start with a clean ~/.claude/settings.json that has no permissions.defaultMode key.
  2. Launch Claude Code: claude.
  3. Press Shift+Tab until the permission mode reads "Bypass Permissions".
  4. Exit the session normally (/exit or Ctrl+D).
  5. Inspect ~/.claude/settings.json.

Expected

The interactive toggle is session-scoped. ~/.claude/settings.json is
unchanged after exit. Re-opening Claude Code starts in the default mode
(or whatever the user explicitly configured).

Actual

~/.claude/settings.json now contains:

{
  "permissions": {
    "...": "...",
    "defaultMode": "bypassPermissions"
  }
}

Every subsequent claude invocation starts in bypass-permissions mode
silently, without the user opting in again.

Why this matters

  • Bypass mode disables permission prompts for tool use. Persisting it as a

default across all future sessions is a security-sensitive change that the
user did not explicitly request via settings.

  • The setting is applied globally (user settings.json), so it affects every

project, not just the one where the toggle was used.

  • There is no in-UI affordance indicating "this toggle will be remembered

forever" — users reasonably expect interactive mode toggles to be ephemeral.

Workaround

I currently mitigate this with a SessionEnd hook that strips the key on
every exit:

{
  "hooks": {
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq 'del(.permissions.defaultMode)' ~/.claude/settings.json > /tmp/.claude_settings_tmp.json && mv /tmp/.claude_settings_tmp.json ~/.claude/settings.json"
          }
        ]
      }
    ]
  }
}

This works but is clearly a workaround for behavior that should not happen
in the first place.

Suggested fix

  • Treat interactive Shift+Tab permission-mode toggles as session-scoped

only; do not write them to settings.json.

  • If persistence is desired, gate it behind an explicit user action

(e.g. a confirmation: "Make this the default for new sessions?") rather
than silently writing on toggle.

  • At minimum, never persist bypassPermissions as a default without an

explicit, separate confirmation step.

Environment

  • Claude Code version: 2.1.138
  • OS: macOS (Darwin 25.4.0)
  • Settings file affected: ~/.claude/settings.json (global user settings)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗