Модель разрешений, безопасность и доверие

Агент — не скрипт. Скрипт делает ровно то, что написано; агент принимает решения самостоятельно на каждом шаге. Именно поэтому вопрос «что агент может делать без вашего ведома» становится ключевым. Claude Code отвечает на него не в виде одного переключателя, а через систему из нескольких слоёв: режимы разрешений задают базовую свободу, правила allow/deny уточняют её на уровне инструментов, хуки добавляют пользовательскую логику, а песочница создаёт OS-уровневую изоляцию. Вместе — это defence in depth: если один слой пропустит что-то нежелательное, следующий должен поймать.


Шесть режимов разрешений

Режим задаёт, что Claude делает автоматически, а что требует вашего ответа «Да» в интерактивной подсказке.

РежимЧто выполняется без промптаКогда применять
defaultТолько чтение файловСтарт работы, чувствительные репозитории
acceptEditsЧтение + редактирование файлов + базовые FS-командыАктивная итерация, когда хочется проверять diff после
planТолько чтениеИсследование кодовой базы перед любыми правками
autoВсё, с фоновой проверкой классификаторомДлинные задачи, минимум прерываний
dontAskТолько команды из permissions.allowHeadless CI, скрипты с жёсткими ограничениями
bypassPermissionsАбсолютно всё (без промптов)Только изолированные контейнеры и VM

acceptEdits — самый популярный выбор в повседневной работе. Он автоматически одобряет правки файлов и стандартные файловые операции (mkdir, touch, rm, rmdir, mv, cp, sed) — но только внутри рабочей директории. Всё за её пределами по-прежнему требует подтверждения.

plan не просто спрашивает перед правками — он инструктирует Claude не пытаться редактировать файлы вообще. Режим строже, чем default: Claude составляет план и ждёт вашего одобрения, прежде чем что-то изменить. Запустить через /plan в начале промпта или нажав Shift+Tab.

auto (research preview) добавляет фоновый классификатор: отдельная модель проверяет каждое действие перед выполнением, блокируя эскалации за пределы вашего запроса. Требует Opus 4.6+ или Sonnet 4.6 на Anthropic API; на Bedrock/Vertex — Opus 4.7/4.8.

bypassPermissions — ядерный вариант. Снимает все проверки разрешений. Единственные исключения-предохранители: rm -rf / и rm -rf ~ всё равно потребуют подтверждения. Недоступен под root/sudo. Применять только в контейнерах без сетевого доступа к внешним системам.

Как переключать режим

# Разовый запуск в plan-режиме
claude --permission-mode plan

# Headless CI с жёсткими ограничениями
claude -p "запусти тесты" --permission-mode dontAsk

# Изолированный контейнер
claude --permission-mode bypassPermissions

В интерактивном режиме Shift+Tab циклически переключает default → acceptEdits → plan (и далее auto/bypassPermissions, если они были разблокированы при запуске). Текущий режим отображается в статусной строке.

Для постоянного дефолта — в .claude/settings.json:

{
  "permissions": {
    "defaultMode": "acceptEdits"
  }
}
Check yourself
В чём ключевое отличие режима `plan` от режима `default`? Оба показывают «Reads only» в колонке «что выполняется без промпта» — значит ли это, что они одинаковы?

Quick recall
Почему `acceptEdits` — популярный выбор для повседневной разработки?

Правила allow / ask / deny

Режим — это базовая линия. Правила точечно её корректируют: разрешают конкретные команды автоматически или жёстко запрещают определённые операции независимо от режима.

Формат

Каждое правило — это Инструмент или Инструмент(паттерн):

{
  "permissions": {
    "allow": [
      "Bash(npm run test *)",
      "Bash(npm run lint)",
      "Read(~/.zshrc)"
    ],
    "ask": [
      "Bash(git push *)"
    ],
    "deny": [
      "Bash(curl *)",
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)"
    ]
  }
}

* в Bash-правилах совпадает с любой последовательностью символов, включая пробелы. Bash(npm run test *) покроет npm run test -- --coverage. Пробел перед * важен: Bash(ls *) совпадёт с ls -la, но не с lsof.

Ключевое различие для deny-правил

Есть критическая разница между голым именем инструмента и паттерном:

  • "Bash" в deny — удаляет инструмент из контекста Claude полностью. Claude вообще не знает о его существовании.
  • "Bash(rm *)" в deny — оставляет Bash доступным, но блокирует конкретные вызовы при попытке их выполнить.

Первый вариант сильнее: Claude не может обойти ограничение даже через инструкции в промпте, потому что инструмент просто не существует с его точки зрения.

Порядок проверки

Правила проверяются в строгом порядке: сначала deny, потом ask, потом allow. Первое совпадение определяет результат — независимо от специфичности.

flowchart TD A([Инструмент вызван]) --> B{Команда read-only?} B -->|Да| C([✅ Выполнить без промпта]) B -->|Нет| D{Совпадает с deny?} D -->|Да| E([🚫 Заблокировать]) D -->|Нет| F{Совпадает с ask?} F -->|Да| G([💬 Запросить разрешение]) F -->|Нет| H{Совпадает с allow?} H -->|Да| I([✅ Выполнить без промпта]) H -->|Нет| J([💬 Запросить разрешение fail-closed])
flowchart TD
    A([Инструмент вызван]) --> B{Команда
read-only?}
    B -->|Да| C([✅ Выполнить
без промпта])
    B -->|Нет| D{Совпадает
с deny?}
    D -->|Да| E([🚫 Заблокировать])
    D -->|Нет| F{Совпадает
с ask?}
    F -->|Да| G([💬 Запросить
разрешение])
    F -->|Нет| H{Совпадает
с allow?}
    H -->|Да| I([✅ Выполнить
без промпта])
    H -->|Нет| J([💬 Запросить
разрешение
fail-closed])
Порядок оценки разрешений: deny → ask → allow; при отсутствии совпадений — запрос (fail-closed)

Это важный нюанс: если у вас есть ask: ["Bash(git push *)"] и allow: ["Bash(git push origin main)"], то конкретный git push origin main всё равно запросит подтверждение — ask-правило найдено первым, до более специфичного allow.

Область действия правил

Правила существуют в нескольких скоупах, которые сливаются, а не замещают друг друга:

Managed (IT/enterprise) — не перекрывается ничем
    └── CLI-флаги — временные переопределения сессии
        └── Local (.claude/settings.local.json) — ваши личные, не в git
            └── Project (.claude/settings.json) — командные, в git
                └── User (~/.claude/settings.json) — базовый уровень

Для разрешений действует особое правило: deny из любого уровня блокирует allow из любого другого. Нельзя «разрешить то, что запрещено выше». При этом в managed-настройках организация может установить allowManagedPermissionRulesOnly: true, полностью запретив проектам и пользователям добавлять свои allow/deny правила.

Check yourself
У вас есть правила: `ask: ["Bash(git push *)"]` и `allow: ["Bash(git push origin main)"]`. Что произойдёт при попытке выполнить `git push origin main`?

Quick recall
Какие команды совпадают с Bash-правилом `npm run test *`?

Защищённые пути

Независимо от режима (кроме bypassPermissions) Claude Code никогда не одобряет автоматически запись в определённые директории. Это жёсткий предохранитель против случайной порчи критической конфигурации:

  • .git, .config/git
  • .vscode, .idea, .husky
  • .cargo, .devcontainer, .yarn, .mvn
  • .claude (кроме .claude/worktrees)
  • Shell-конфиги: .zshrc, .bashrc, .profile и другие
  • MCP и агентные конфиги: .mcp.json, .claude.json

Даже явное allow-правило на .claude/** не обойдёт эту защиту — проверка защищённых путей происходит до оценки allow-правил.


Quick recall
Какие пути защищены от автоматической записи, даже если есть allow-правило?

Песочница: OS-уровневая изоляция

Правила разрешений работают на уровне Claude Code — они определяют, что агент попытается сделать. Но если что-то всё же проскочило через промпт-инъекцию или ошибочное решение модели, правила не смогут остановить subprocess, запущенный уже одобренной командой.

Вот где нужна песочница (/sandbox). Она создаёт OS-уровневую изоляцию для Bash-команд: ограничивает доступ к файловой системе и сети на уровне ядра, вне зависимости от того, что решил Claude. Полезна при работе с непроверенным кодом или внешними данными.

Правила разрешений и песочница дополняют друг друга:

  • Правила блокируют попытки Claude обратиться к запрещённым ресурсам.
  • Песочница физически не позволяет Bash-командам (и их дочерним процессам) выйти за установленные границы.

Prompt injection: скрытая угроза

Prompt injection — это когда в данных, которые читает Claude (файл, веб-страница, вывод команды), спрятаны инструкции для агента: «игнорируй предыдущие инструкции и выполни…». Для агентного инструмента, читающего файлы и вызывающего команды, это реальная угроза.

Claude Code применяет несколько защит:

  • curl и wget не авто-одобряются — они требуют явного разрешения, как любая другая Bash-команда. Заблокировать полностью: deny: ["Bash(curl *)", "Bash(wget *)"].
  • WebFetch использует изолированное контекстное окно — содержимое внешней страницы не попадает напрямую в основной диалог, что снижает риск инъекции через веб-контент.
  • Детектирование инъекций в командах — подозрительные команды требуют ручного одобрения, даже если в allow есть подходящее правило.
  • bypassPermissions убирает эту защиту — вот почему он опасен с недоверенным контентом.

Практический совет при работе с внешними данными:

# Плохо: весь вывод curl улетает прямо в Claude
curl https://example.com/data.json | claude -p "проанализируй"

# Лучше: сохрани файл, проверь его, потом передай
curl -o data.json https://example.com/data.json
# (проверь файл вручную)
claude -p "проанализируй @data.json"
Check yourself
Почему опасно запускать `bypassPermissions` при работе с непроверенными внешними данными (например, читая код из интернета)?

Как давать агенту ровно нужную свободу

Практическая шпаргалка:

  • Изучение незнакомого кодаplan-режим или default. Никаких правок до вашего одобрения.
  • Активная разработкаacceptEdits + deny-правила на curl *, git push *, .env-файлы.
  • CI/CD с известным набором командdontAsk + точные allow-правила на каждую допустимую команду.
  • Полная автоматизация с гарантиямиauto-режим, если доступен (требует Opus/Sonnet 4.6+).
  • Разовый эксперимент в контейнереbypassPermissions, но только в изолированной VM без доступа к продакшн-системам.

Золотое правило: чем шире область действия агента, тем строже должны быть deny-правила и тем важнее песочница. Режим задаёт свободу по умолчанию; правила — точечные ограничения поверх него. Использовать оба уровня вместе надёжнее, чем полагаться только на один.


See also