ИИ-агенты и автоматизация
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.json | 104 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:
- Клон на другом компьютере. Там глобального исключения нет, и
git add .подхватывает файл. - Папка, которая стала репозиторием позже. Файл появился до
git init— исключение не прописалось. - Файл, созданный или закоммиченный руками. Документация отдельно оговаривает: такой файл в
.gitignoreпридётся добавить самостоятельно. - Коммит, который делает сам агент. В 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 | Доля |
|---|---|---|
| gitleaks | 564 | 50,3 % |
| TruffleHog | 643 | 57,3 % |
| Ни один из двух | 215 | 19,2 % |
У ключа провайдера есть префикс и длинная случайная строка — сканер его узнаёт. Пароль после PGPASSWORD=, sshpass -p, mysql -p или в заголовке Bearer внутри curl формы не имеет. Для сканера это часть командной строки.
Если у вас настроен только gitleaks в pre-commit, примерно каждый пятый такой файл всё равно уедет. Сканеру нужны отдельные правила под PGPASSWORD=, sshpass -p, mysql -p и заголовки Bearer — форматов ключей мало.
Как проверить свой репозиторий за пять минут
Начните с того, что видно снаружи, потом смотрите локально. Все команды — для корня проекта.
- Файл сейчас в репозитории?
``bash git ls-files | grep -E '(^|/)\.claude/settings(\.local)?\.json$' ``
- Он когда-нибудь был закоммичен? История важнее текущего состояния: Apiiro нашла 734 секрета только в прошлых версиях файла.
``bash git log --all --oneline -- .claude/settings.local.json ``
- Что внутри? Откройте каждую копию на машине и посмотрите 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 ``
- Убрать файл из-под git и закрыть путь назад:
``bash git rm --cached .claude/settings.local.json echo '.claude/settings.local.json' >> .gitignore ``
- Переписать правила на шаблоны. Вместо одобрения дословной команды — правило вида
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_, поэтому найти их грепом из списка выше просто.
Что делать дальше:
- Отозвать ключ в кабинете и выпустить новый. Полностью ключ показывается один раз, при создании, и восстановить его потом нельзя — только заменить. Не тратьте время на выяснение, тот ли это ключ: если строка
kd_live_лежит в файле, который мог уйти в git, он скомпрометирован. - Положить новый ключ в переменную окружения, например
KEYDEALER_API_KEY, как в документации. Тогда агент запишет в правило$KEYDEALER_API_KEY, а не сам ключ. - Ограничить ключ. Дневной лимит в рублях, месячный лимит и список разрешённых моделей превращают утечку из угрозы балансу в неприятность на один день. Как выбрать величину, разобрано в статье про лимит расходов на ключ.
- Завести агенту отдельный ключ. Тогда утёкший ключ из
settings.local.jsonотзывается один, а прод продолжает работать. Чтобы прикинуть, сколько стоит день работы агента и какой лимит ему ставить, пригодятся рублёвые ставки из таблицы стоимости миллиона токенов. - Добавить префикс в сканер. Формата
kd_live_в стандартных правилах gitleaks может не быть. Своё правило с регулярным выражениемkd_live_[A-Za-z0-9_-]+закрывает этот пробел.
Для агентов, которые выполняют команды без вас, полезно ограничить и окружение: песочница отрезает агенту доступ к файлам и сети вне проекта. Как это делает открытая утилита Anthropic, мы разбирали в обзоре sandbox-runtime.
Где ещё агенты оставляют секреты, кроме Claude Code
Привычка, из-за которой течёт, у всех агентов одна: секрет набран прямо в команде, а агент эту команду записывает. Apiiro проверила и соседние файлы.
| Файл | Проверено | С реальным секретом |
|---|---|---|
Общий .claude/settings.json, который коммитят намеренно | 76 011 | 298 файлов |
Сохранённые диалоги агентов: .specstory, aider, экспорт Cursor | 2523 | 120 файлов в 87 репозиториях |
Файлы памяти агентов вроде MEMORY.md | 1200 | 9 репозиториев |
| Заметки о передаче задач и деплое | 2095 | 33 файла |
| Настройки автоодобрения Copilot в VS Code | 173 | 9 репозиториев |
Треть заметок о передаче задач с секретом написал сам агент. За пределами 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 новый ключ стоит сразу ограничить дневным лимитом в рублях и списком разрешённых моделей, чтобы следующая утечка стоила копейки.