Claude Code сохраняет токены в файл, и 1 122 репозитория выдали их публично
Когда разработчик жмёт в Claude Code «Yes, and don't ask again», агент записывает команду целиком в .claude/settings.local.json. Если в ней был токен или пароль, он оказывается в файле. Защиту от git Claude добавляет только в глобальный exclude на ноутбуке, поэтому файл спокойно коммитится. По данным Apiiro, в публичных репозиториях нашли 104 185 копий, в 1 122 из них был хотя бы один секрет.
AI-обработка оригинала GitLab Blog; редакция Hamidun News
Знакомая ситуация: агент просит разрешения запустить shell-команду, вы устали подтверждать одно и то же и жмёте «Yes, and don't ask again». Claude Code запоминает выбор и записывает команду в файл .claude/settings.local.json внутри проекта. Проблема в том, что команда сохраняется буквально. Если вы дёргали API через curl с заголовком PRIVATE-TOKEN, токен окажется в этом файле в открытом виде.
Почему файл уезжает в репозиторий
Чтобы файл не попадал в git, Claude Code добавляет его в личный глобальный exclude разработчика, а не в .gitignore проекта. Эта защита живёт на одном ноутбуке и не передаётся вместе с репозиторием. Коллега, CI-окружение или второй компьютер этого исключения не знают. git add . подхватывает файл, и он уходит туда, где лежит репозиторий.
Масштаб оценила компания Apiiro в начале ноября 2026 года. В публичных репозиториях нашлось 104 185 копий файла, и в 1 122 из них был хотя бы один секрет. Ещё сотни секретов остались только в истории, в файлах, которые уже удалили. Удаление файла не отменяет утечку: токен всё равно лежит в старых коммитах.
Руководство GitLab написано для тех, кто хранит код у них, но логика переносится на любой git-хостинг. GitLab при этом заявляет, что собственные инфраструктурные секреты защищены.
Как закрыть дыру: четыре слоя
Группа настраивается один раз, дальше защита работает сама. Слои идут от простого к сложному.
1. .gitignore. Самый дешёвый вариант: строка .claude/settings.local.json в каждом репозитории. На тарифах Premium и Ultimate её можно положить в .gitignore шаблонного проекта группы, и все новые проекты унаследуют её сами.
2. Push-правило (Premium и Ultimate). В настройках группы, в разделе запрещённых имён файлов, указывается регулярное выражение (^|/)\\.claude/settings\\.local\\.json$. Любой push с таким файлом, в корне или в подпапке, на любой ветке, будет отклонён, а разработчик увидит сообщение с шаблоном.
3. Secret Push Protection (Ultimate). Этот слой смотрит не на имя файла, а на содержимое пуша. Если находится токен известного формата, пуш отклоняется. Это спасёт и тогда, когда секрет попал в файл с другим именем.
4. Политика сканирования (Ultimate). Политика на верхнем уровне группы запускает Secret Detection в каждом проекте, даже без .gitlab-ci.yml, и отдельные проекты не могут её отключить. Одно правило срабатывает на каждом пайплайне, второе по недельному расписанию. С переменной SECRET_DETECTION_HISTORIC_SCAN: 'true' расписание проверяет всю историю, а не только новые коммиты.
Подводные камни
У push-правил есть два ограничения. Во-первых, они проверяют только добавление файлов, а не изменения уже отслеживаемых, поэтому сначала нужно убрать существующие копии. Во-вторых, правило группы копируется только в проекты, созданные после его появления. Для старых проектов его нужно задать отдельно, например через API: POST /api/v4/projects/<id>/push_rule с параметром file_name_regex. Если у проекта уже есть свои правила, используйте PUT, иначе получите ошибку 422 Project push rule exists.
Как понять, есть ли у вас проблема
Сначала нужен список затронутых репозиториев. Есть три способа:
- GitLab Duo Agentic Chat. Вы просите чат найти все проекты группы, где когда-либо был этот файл, включая удалённые копии и другие ветки. На группу примерно из ста проектов уходит несколько минут. Зато он находит то, что поиск не видит.
- Поиск по коду (Premium и Ultimate). Работает быстро, но видит только дефолтную ветку в её нынешнем состоянии. Синтаксис зависит от движка: для exact code search
file:\\.claude/settings\\.local\\.json$с регулярками, для advanced searchfilename:settings.local.json path:.claude. В API держитеexclude_forks=false, иначе форки пропадут из выдачи. - Commits API (все тарифы). Запрос
repository/commits?path=.claude/settings.local.json&all=trueпо каждому проекту показывает, существовал ли файл на какой-либо ветке. Пустой ответ значит, что файла не было никогда. Форки проверяются так же, как обычные проекты.
Что делать на практике
Начните с поиска по истории, а не по текущему состоянию: удалённые файлы опаснее всего, потому что про них забывают. Всё, что нашлось в файле, считайте скомпрометированным и перевыпускайте, даже если репозиторий приватный. Затем включайте защиту: хотя бы .gitignore и push-правило, а при Ultimate ещё и проверку содержимого.
Отдельная мысль для команд, которые внедряют агентов: кнопка «больше не спрашивать» превращает одноразовое разрешение в постоянную запись о командах, и секреты из этих команд попадают туда вместе с ними. Не передавайте токены агенту аргументами командной строки, используйте переменные окружения или менеджер секретов, тогда сохранённая команда будет безопасной.
Ограничение: в предоставленном тексте руководство обрывается до раздела с массовой очисткой, поэтому порядок очистки истории нужно смотреть в оригинале.
- 12 нояб. 2026 г.Claude Fable 5.2 в Devin набрал 49,1% на FrontierCode 2.0 против 32,4% у 5.1
- 12 нояб. 2026 г.Автор «Точек над ИИ» заменил Notion и CRM агентами: 80+ скиллов вместо сервисов
- 12 нояб. 2026 г.ChatGPT забрал 81,4% трафика шести ИИ-чатботов в исследовании Graphite
- 12 нояб. 2026 г.Devin Security получил Claude Mythos 5.2: 73,5 балла против 32,7 у Opus 5.5
Вопросы и ответы по материалу
Что известно по теме: почему файл уезжает в репозиторий?
Чтобы файл не попадал в git, Claude Code добавляет его в личный глобальный exclude разработчика, а не в .gitignore проекта. Эта защита живёт на одном ноутбуке и не передаётся вместе с репозиторием. Коллега, CI-окружение или второй компьютер этого исключения не знают. git add . подхватывает файл, и он уходит туда, где лежит репозиторий. Масштаб оценила компания Apiiro в начале ноября 2026 года. В публичных репозиториях нашлось 104 185 копий файла, и в 1 122 из них был хотя бы один секрет.
Что известно по теме: как закрыть дыру: четыре слоя?
Группа настраивается один раз, дальше защита работает сама. Слои идут от простого к сложному. 1. .gitignore. Самый дешёвый вариант: строка .claude/settings.local.json в каждом репозитории. На тарифах Premium и Ultimate её можно положить в .gitignore шаблонного проекта группы, и все новые проекты унаследуют её сами. 2. Push-правило (Premium и Ultimate). В настройках группы, в разделе запрещённых имён файлов, указывается регулярное выражение (^|/)\\.claude/settings\\.local\\.json$.
Что известно по теме: подводные камни?
У push-правил есть два ограничения. Во-первых, они проверяют только добавление файлов, а не изменения уже отслеживаемых, поэтому сначала нужно убрать существующие копии. Во-вторых, правило группы копируется только в проекты, созданные после его появления. Для старых проектов его нужно задать отдельно, например через API: POST /api/v4/projects/<id>/push_rule с параметром file_name_regex. Если у проекта уже есть свои правила, используйте PUT, иначе получите ошибку 422 Project push rule exists.
Соберите рабочего ИИ-агента или сервис своими руками без ручного кода
В Академии Жемала Хамидуна (academy.hamidun.com) открыт бесплатный 72-часовой тест-драйв: интерактивные скетч-уроки по Claude Code и Cursor, живой Tech Radar и готовые шаблоны агентов.
Главное из мира ИИ — раз в неделю
7 ключевых событий недели, отобранных вручную. Без шума, репостов и пресс-релизов.
Готово! Проверьте почту — мы отправили подтверждение.