ИИ-агенты и автоматизация

Claude Code и «don't ask again»: секреты в 1122 файлах

Claude Code и «don't ask again»: секреты в 1122 файлах

Исследователи Apiiro 2 ноября 2026 года посчитали, сколько секретов лежит в публичных файлах .claude/settings.local.json на GitHub: из 104 185 копий реальный пароль, токен или ключ нашёлся в 1122 (1,1 %). Механизм простой — Claude Code по кнопке «Yes, and don't ask again» сохраняет одобренную команду дословно, вместе с паролем внутри. Всего по файлам агентов набралось 2539 секретов в 1994 репозиториях, а gitleaks и TruffleHog вместе пропустили 215 файлов из 1122. Anthropic 7 ноября ответила, что изучает защиту. Ниже — как секрет туда попадает, как проверить свой проект за пять минут и что сделать с ключом к модели, если он уже в файле.

Сколько секретов нашли в settings.local.json на GitHub

По данным Apiiro на 1–3 ноября 2026 года — 1379 разных секретов в 1122 публичных файлах .claude/settings.local.json, а с соседними файлами агентов — 2539 секретов в 1994 репозиториях. Apiiro — компания, которая продаёт инструменты безопасности кода, и это исследование одновременно реклама её продукта. Цифры при этом проверяемые: методика описана подробно, каждый случай с организацией закреплён ссылкой на конкретный коммит. Данные собраны поиском по GitHub с 1 по 3 ноября 2026 года.

Что посчиталиСколько
Публичных копий .claude/settings.local.json104 185 в 103 617 репозиториях
Файлов с реальным секретом1122 (1,1 %)
Разных секретов в этих файлах1379: 636 ключей известных провайдеров и 743 пароля или токена
Из них дают прямой доступ к базе379 паролей к базам и 122 сервисных ключа Supabase
SSH-доступов к публичным серверам43, часть — пароль root в команде sshpass
Всего секретов по всем файлам агентов2539 в 1994 репозиториях
Затронутых организаций63, одна подтвердила, что ключ был рабочим

Среди случаев — облачный ключ самого вендора базы данных с правами управления и без срока действия, пароль к продовой Postgres в Azure, продовый токен Square, пароль владельца базы медицинских записей. И отдельной строкой — ключ в формате OpenAI у открытого проекта с тысячей с лишним звёзд.

Файлы не свежие. В медианном репозитории с секретом файл впервые закоммичен за 217 дней до сбора данных, в 118 репозиториях — больше года назад. 211 форков 74 репозиториев несут те же секреты.

Как пароль попадает в settings.local.json

Через кнопку, которую нажимают на автомате. Claude Code спрашивает разрешение перед каждой новой shell-командой. Если выбрать «Yes, and don't ask again», команда выполнится, а в .claude/settings.local.json появится allow-правило. Документация Claude Code описывает это прямо: правило сохраняется в локальный файл проекта, в корень репозитория.

Правилом становится сама строка команды, целиком. Вы просите агента выяснить, почему не проходит логин на стейджинге. Агент достаёт строку подключения из конфига и предлагает:

PGPASSWORD=s3cr3t psql -h db.example.com -U app -c "select count(*) from users"

Вы нажимаете «больше не спрашивать» — и пароль s3cr3t теперь лежит в JSON открытым текстом. Точно так же в файл уезжает curl с заголовком Authorization: Bearer … или mysql -p….

Apiiro воспроизвела поведение на Opus 5.5 и Fable 5.1 и отдельно подчёркивает: так ведёт себя сама программа, а не модель. Чем дольше вы работаете в проекте, тем толще файл. Среди файлов больше 8 КБ секрет есть в каждом десятом, среди файлов меньше 500 байт — меньше чем в одном из пятисот.

Почему файл оказывается на GitHub, если Claude Code его прячет

Защита есть, но работает на одной машине. По документации, когда Claude Code впервые пишет этот файл в git-репозитории, он добавляет **/.claude/settings.local.json в глобальный файл исключений git — core.excludesFile или ~/.config/git/ignore. В .gitignore самого репозитория правило не попадает.

Отсюда дыры, которые перечисляет Apiiro:

  1. Клон на другом компьютере. Там глобального исключения нет, и git add . подхватывает файл.
  2. Папка, которая стала репозиторием позже. Файл появился до git init — исключение не прописалось.
  3. Файл, созданный или закоммиченный руками. Документация отдельно оговаривает: такой файл в .gitignore придётся добавить самостоятельно.
  4. Коммит, который делает сам агент. В 539 из 1105 отслеженных репозиториев с секретом (48,8 %) файл изменил коммит с соавтором Claude.

Последний пункт стороны трактуют по-разному. Apiiro считает, что агент сам коммитит файл. Борис Черни, руководитель Claude Code, ответил на Hacker News, что программа автоматически исключает файл при создании, а значит, найденные копии были созданы и закоммичены вручную. Обе версии могут быть верны одновременно: исключение живёт на машине, где файл создан, а коммиты делаются в других местах.

Что ответила Anthropic

Пока только словами: релиза нет. 7 ноября 2026 года публикация Apiiro вышла в топ Hacker News и набрала больше 430 баллов. Борис Черни написал в обсуждении три вещи:

  • Claude Code исторически не вычищал секреты из команд, но команда «изучает, что можно сделать», и базовое сканирование секретов — один из вариантов, которые будут прототипировать.
  • Ручные allow- и deny-списки он назвал устаревшим подходом и предложил вместо них auto mode — режим, где действия вместо уставшего человека проверяет классификатор. Как он устроен и почему его включили по умолчанию, мы разбирали в статье про auto mode в Claude Code.
  • Сканирование секретов стоит включить в любом случае, каким бы агентом вы ни пользовались, — GitHub и другие хостинги кода его предлагают.

Сроков исправления в обсуждении нет. Apiiro добавляет, что о механизме пользователи сообщали в issues Claude Code с августа 2025 года, и три таких обращения закрылись автоматически.

Почему gitleaks и TruffleHog пропускают такие секреты

Потому что пароль внутри команды не похож на ключ: на файлах Apiiro оба сканера вместе пропустили 215 из 1122. Сканеры ищут ключи по форме, а пароль в команде выглядит как обычное слово. Apiiro прогнала оба инструмента по всем 104 185 файлам, без проверки найденного на живость.

СканерНашёл файлов из 1122Доля
gitleaks56450,3 %
TruffleHog64357,3 %
Ни один из двух21519,2 %

У ключа провайдера есть префикс и длинная случайная строка — сканер его узнаёт. Пароль после PGPASSWORD=, sshpass -p, mysql -p или в заголовке Bearer внутри curl формы не имеет. Для сканера это часть командной строки.

Если у вас настроен только gitleaks в pre-commit, примерно каждый пятый такой файл всё равно уедет. Сканеру нужны отдельные правила под PGPASSWORD=, sshpass -p, mysql -p и заголовки Bearer — форматов ключей мало.

Как проверить свой репозиторий за пять минут

Начните с того, что видно снаружи, потом смотрите локально. Все команды — для корня проекта.

  1. Файл сейчас в репозитории?

``bash git ls-files | grep -E '(^|/)\.claude/settings(\.local)?\.json$' ``

  1. Он когда-нибудь был закоммичен? История важнее текущего состояния: Apiiro нашла 734 секрета только в прошлых версиях файла.

``bash git log --all --oneline -- .claude/settings.local.json ``

  1. Что внутри? Откройте каждую копию на машине и посмотрите allow-список:

``bash find ~ -path '/.claude/settings.local.json' 2>/dev/null grep -nE 'PGPASSWORD=|sshpass -p|mysql .-p|Bearer |postgres(ql)?://|kd_live_|sk-' .claude/settings.local.json ``

  1. Убрать файл из-под git и закрыть путь назад:

``bash git rm --cached .claude/settings.local.json echo '.claude/settings.local.json' >> .gitignore ``

  1. Переписать правила на шаблоны. Вместо одобрения дословной команды — правило вида Bash(npm run ). В документации Claude Code звёздочка означает любую последовательность символов, а запись Bash(ls:) эквивалентна Bash(ls *).

Нашли секрет — порядок жёсткий: сначала отозвать и заменить, потом чистить историю. Удаление файла не стирает его из форков и клонов. Почему первый шаг нельзя переставлять, мы разбирали в материале как хранить API-ключи.

Что в этой истории пока не подтверждено

Три оговорки, без которых цифры легко пересказать неверно.

«Реальный секрет» не значит «рабочий». Apiiro не проверяла ни один ключ и не обращалась ни к одному хосту. В её терминах реальный секрет — значение в формате известного провайдера или пароль рядом с публичным адресом, прошедшее фильтры ложных срабатываний и проверку отдельной LLM по рубрике. Рабочим подтверждён один ключ — его владелец сам сообщил об этом.

Защиты от Anthropic пока нет. Есть обещание прототипировать сканирование. Когда и в каком виде оно выйдет, в открытой документации не опубликовано.

Сравнение с другими агентами сделано по документации. Apiiro сравнила 16 агентов и пишет, что только Claude Code подтверждённо сохраняет полную одобренную команду в файл проекта по умолчанию. Тестов каждого агента в публикации нет.

Что сделать с ключом KeyDealer, если он попал в файл

Ключ к модели в allow-правиле — такой же секрет, как пароль к базе, и тратит он ваши деньги. Если вы подключали Claude Code через свой ключ или просили агента «проверить баланс через curl», загляните в файл прямо сейчас. Ключи KeyDealer начинаются с kd_live_, поэтому найти их грепом из списка выше просто.

Что делать дальше:

  1. Отозвать ключ в кабинете и выпустить новый. Полностью ключ показывается один раз, при создании, и восстановить его потом нельзя — только заменить. Не тратьте время на выяснение, тот ли это ключ: если строка kd_live_ лежит в файле, который мог уйти в git, он скомпрометирован.
  2. Положить новый ключ в переменную окружения, например KEYDEALER_API_KEY, как в документации. Тогда агент запишет в правило $KEYDEALER_API_KEY, а не сам ключ.
  3. Ограничить ключ. Дневной лимит в рублях, месячный лимит и список разрешённых моделей превращают утечку из угрозы балансу в неприятность на один день. Как выбрать величину, разобрано в статье про лимит расходов на ключ.
  4. Завести агенту отдельный ключ. Тогда утёкший ключ из settings.local.json отзывается один, а прод продолжает работать. Чтобы прикинуть, сколько стоит день работы агента и какой лимит ему ставить, пригодятся рублёвые ставки из таблицы стоимости миллиона токенов.
  5. Добавить префикс в сканер. Формата kd_live_ в стандартных правилах gitleaks может не быть. Своё правило с регулярным выражением kd_live_[A-Za-z0-9_-]+ закрывает этот пробел.

Для агентов, которые выполняют команды без вас, полезно ограничить и окружение: песочница отрезает агенту доступ к файлам и сети вне проекта. Как это делает открытая утилита Anthropic, мы разбирали в обзоре sandbox-runtime.

Где ещё агенты оставляют секреты, кроме Claude Code

Привычка, из-за которой течёт, у всех агентов одна: секрет набран прямо в команде, а агент эту команду записывает. Apiiro проверила и соседние файлы.

ФайлПровереноС реальным секретом
Общий .claude/settings.json, который коммитят намеренно76 011298 файлов
Сохранённые диалоги агентов: .specstory, aider, экспорт Cursor2523120 файлов в 87 репозиториях
Файлы памяти агентов вроде MEMORY.md12009 репозиториев
Заметки о передаче задач и деплое209533 файла
Настройки автоодобрения Copilot в VS Code1739 репозиториев

Треть заметок о передаче задач с секретом написал сам агент. За пределами GitHub картина та же: 126 из 31 053 проверенных Spaces на Hugging Face содержат settings.local.json, а на GitLab.com в 2 из 69 публичных копий лежит реальный секрет.

Отсюда правило шире одной кнопки: папки .claude/, .cursor/, .gemini/, .specstory/ и файлы памяти агентов стоит считать такими же секретоносными, как .env, — и на ноутбуке, и в репозитории. Включите их в сканирование истории в CI и в шаблон .gitignore для новых проектов. А ключ к моделям для агента заведите отдельно, с лимитом и списком моделей, — это делается за минуту в кабинете на keydealer.ru/login.

Частые вопросы

Что такое .claude/settings.local.json в Claude Code?

Это личный файл настроек одного проекта. Claude Code хранит в нём ваши персональные переопределения и разрешения на команды, которые вы одобрили кнопкой «Yes, and don't ask again». Файл лежит в корне репозитория рядом с общим .claude/settings.json, но коммитить его не задумано.

Почему Claude Code сохраняет пароль в settings.local.json?

Потому что кнопка «Yes, and don't ask again» записывает в файл разрешение в виде самой команды. Если в команде был пароль, токен или строка подключения к базе, секрет попадает в allow-правило дословно и лежит там, пока правило не удалят руками.

Попадает ли settings.local.json в git автоматически?

По документации Claude Code — нет. Когда программа впервые создаёт этот файл в git-репозитории, она добавляет его в глобальный список исключений git на вашей машине. Это не спасает клон на другом компьютере, папку, которая стала репозиторием позже, и файл, созданный или закоммиченный вручную, — поэтому Apiiro и нашла его в 103 617 публичных репозиториях.

Достаточно ли удалить settings.local.json из репозитория?

Нет. Секрет остаётся в истории коммитов, во всех форках и клонах. Apiiro нашла 734 секрета в прошлых версиях файла, которых нет ни в одной текущей копии. Сначала секрет отзывают и меняют, потом чистят репозиторий.

Ловят ли такие утечки gitleaks и TruffleHog?

Частично. На 1122 файлах с реальным секретом gitleaks сработал на 564, TruffleHog — на 643, а 215 файлов не заметил ни один. Сканеры ищут ключи по известным форматам и пропускают пароль, набранный после PGPASSWORD=, sshpass -p или в заголовке Bearer внутри команды.

Что делать, если в файл попал ключ API к модели?

Отозвать ключ в кабинете провайдера и выпустить новый, затем удалить правило из файла и передавать ключ дальше только через переменную окружения. В KeyDealer новый ключ стоит сразу ограничить дневным лимитом в рублях и списком разрешённых моделей, чтобы следующая утечка стоила копейки.

Источники