Daily MaverickFoot in mouth — politicians talk sh#t while South Africans live in itPunchJUST IN: Dangote refinery opens N2.15tn IPO on NGXInquirerMarcos: Gov’t accelerating public spending to spur economic growthInquirer EntertainmentAJ Raval stars in short film set for international releaseוואלהכתב אישום חמור הוגש נגד הדוקר בבריכה של בן ה-7The Jerusalem PostTrump to review 9/11 victims' request to declassify records on alleged Saudi links to attacksESPNWeek 2 AP poll reaction: What's next for each Top 25 teamCollider‘John Wick’ Meets ‘Jason Bourne’ in Jon Bernthal’s Spy Smash Officially on Prime VideoSouth China Morning PostHow an AI plot targeted Malaysia’s elections and exposed deep data risksRTL BoulevardTrein ramt vrachtwagen op spoorwegovergang ErmeloSCMP ChinaBeijing hails Taiwanese scholar’s rare proposal on reunificationLa PresseUn passage souterrain pourrait remplacer le viaduc Rosemont-Van Horne
The Daily Newsstand · Free, Always
Monday, September 14, 2026

«Уберу перед пушем» и другие способы потерять секреты. Чек-лист для самопроверки

Translate

TL;DR; Разбираем базовую, но от этого не менее болезненную тему: что такое секреты, почему разработчики с завидным упорством продолжают их коммитить, где таятся главные дыры и как один забытый токен может обернуться миллионными убытками для бизнеса.

Всё тайное становится явным

Представьте: ваш коллега забыл один токен в CI-конфиге личного форка. Один токен с правами на публикацию пакетов. Злоумышленник находит его во время того, как раннер на выделенном сервере выполняет деплой (пока что у злоумышленника нет доступа к другим частям), перехватывает и внедряет малварь напрямую в собираемый npm-пакет или Docker-образ компании. Во время следующего автоматического релиза заражённая библиотека уходит в продакшен тысячи B2B-клиентов. В код вшивается бэкдор, превращающий каждое клиентское приложение в точку входа. В итоге один утекающий токен разработчика приводит не к локальному инциденту, а к масштабному скандалу уровня SolarWinds и отзыву лицензий у компании. 

Всем привет! Я Натан, техлид модуля Secrets в CodeScoring. Мы разрабатываем on-premise-решение для безопасной работы с кодом и инфраструктурой. В этой статье я расскажу, что мы подразумеваем под секретами, почему они упорно продолжают утекать и к каким катастрофам это приводит на практике. Статья будет полезна тимлидам, разработчикам и DevSecOps-инженерам, которые хотят навести порядок в своих репозиториях.

И чтобы не заканчивать на страшном — в конце статьи чек-лист: как за пару минут проверить репозиторий на забытые секреты и что делать, если что-то нашлось. Спойлер: «просто удалить из кода» не поможет.

Что такое секреты в коде

Давайте представим, что вы автоматически публикуете Python-пакеты во время очередного релиза:

import os
import subprocess

PACKAGE_NAME = "my-awesome-lib"
VERSION = "1.0.4"

PYPI_API_TOKEN = "pypi-AgEIcHlwaS5vcmcCAWIAAAYgxbyLvb9egSCECeOdB3qW3h4oXEoNC6kJI0NtaFOQlUY"

def publish_package():
    print(f"Публикация версии {VERSION}...")
    
    cmd = [
        "twine", "upload",
        "--username", "__token__",
        "--password", PYPI_API_TOKEN,
        "dist/*"
    ]
    
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode == 0:
        print("Пакет успешно опубликован!")
    else:
        print(f"Ошибка публикации: {result.stderr}")

if __name__ == "__main__":
    publish_package()

Теперь посмотрите на код внимательно. Нас интересует вот эта строка: PYPI_API_TOKEN = "pypi-AgEIcHlwaS5vcmcCAWIAAAYgxbyLvb9egSCECeOdB3qW3h4oXEoNC6kJI0NtaFOQlUY".

Это токен доступа к PyPI — реестру пакетов Python. Грубо говоря, это ключ, который подтверждает: «Да, этот пакет публикует именно наша компания, а не кто-то другой».

В чём проблема? Токен написан прямо в коде, открытым текстом. Он не берётся, например, из хранилища. Он просто лежит в файле как обычная строка. А значит, любой, кто видит этот файл, видит и токен.

Если злоумышленник получит доступ к исходнику этого скрипта, то сможет опубликовать свой зловредный пакет от имени компании.

Или где-то в конфигурации пайплайна CI/CD всплывёт:

name: Publish Python Package to PyPI

on:
  release:
    types: [published]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install build twine

      - name: Build and publish
        env:
          # ОШИБКА: Захардкоженный секрет вместо ${{ secrets.PYPI_TOKEN }}
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: pypi-AgEIcHlwaS5vcmcCAWIAAAYgxbyLvb9egSCECeOdB3qW3h4oXEoNC6kJI0NtaFOQlUY
        run: |
          python -m build
          twine upload dist/*

Здесь секрет прячется в блоке env шага «Build and publish»: TWINE_PASSWORD: pypi-AgEIcHlwaS5vcmcCAWIAAAYgxbyLvb9egSCECeOdB3qW3h4oXEoNC6kJI0NtaFOQlUY.

Как и в примере выше, API-токен лежит в конфигурации CI/CD в открытую. И дальше — тот же сценарий: любой, кто получит доступ к конфигурации, сможет совершить публикацию пакета от имени компании.

Разработчики часто забывают добавить .env-файл в список исключений или подкладывают переменные с чувствительными данными в файл, и он вместе со всем проектом выкладывается в интернет. И вот ключ от продакшена уже лежит в открытом доступе.

Тот самый забытый пароль или API-ключ — это то, что называют секретами. Если проще: секрет — это любая строка, файл или ключ, зная который можно зайти туда, куда без него зайти нельзя, или увидеть то, что нельзя видеть всем.

К ним относятся не только пароли. Вот что ещё считается секретом:

  • токены доступа к облачным провайдерам, Telegram-ботам, платежным шлюзам типа ЮKassa;

  • креды для баз данных, например логины, пароли, connection strings;

  • приватные SSH- и GPG-ключи;

  • SSL/TLS-сертификаты.

Всё это цифровые артефакты, которые дают авторизованный доступ к защищённым ресурсам, инфраструктуре или данным. 

И если эти данные попадут наружу, злоумышленнику не нужно будет эксплуатировать сложные уязвимости. Достаточно использовать найденный ключ. Проблема в том, что современная разработка невозможна без секретов. Они нужны для связи компонентов системы. И именно поэтому они так часто оседают там, где их быть не должно.

Где живут секреты и как они утекают

Обычно кажется, что утечки — это результат работы сложных APT-группировок. На деле же секреты просто лежат под ногами. 

По данным GitHub, только за 2025 год в публичных репозиториях засветилось 29 миллионов секретов. Не украдено. Засветилось — самими разработчиками.

Вот топ-6 мест, откуда они утекают чаще всего:

  1. Исходный код (хардкод). «Я захардкожу токен чисто для локальных тестов, а перед пушем в мастер уберу». Разработчик спешил, код прошёл ревью (потому что ревьюер смотрел на бизнес-логику, а не на константы), и токен навсегда вмёрз в историю гита. И вот тут ключевой момент: гит помнит всё. Удалили секрет из кода в следующем коммите? Он всё равно лежит в истории. «Удалить из кода» и «удалить из гита» — очень разные вещи. Стоит держать в голове, что секреты живут не в актуальной версии продукта, а во всех версиях, которые записаны где-либо: в коммитах, в бэкапах, на дисках сотрудников. В некотором смысле это «режиссёрская версия» вашего продукта, которую жаждут увидеть не самые желанные фанаты. 

  2. Бинарник. Даже тут секрет не будет в безопасности. Если секрет — это просто строка в коде, компилятор поместит её в раздел со статическими данными внутри исполняемого файла. Запутывание, или, по-другому, обфускация, тоже не спасает. Такие данные выделяются высокой энтропией — их легко найти в файле. А во время исполнения секрет всё равно должен появиться в памяти в исходном виде: иначе программа просто не сможет им воспользоваться. Вот там его и «ловят» через дамп RAM. Исключение — аппаратные среды доверенного исполнения, так называемые анклавы (например, Trusted Platform Module и производные технологии). Но даже там, без корректной настройки и разработки вокруг этой технологии, есть программные и аппаратные способы достать «зашитый» секрет.

  3. Файлы окружения (.env). Файлы .env придумали именно для того, чтобы отделить конфигурацию от кода. Но стоит кому-то забыть добавить .env в .gitignore, как весь набор кредов от продакшена улетает в общий репозиторий. А дальше — как в пункте про хардкод: даже если спохватиться через час, удалить файл и добавить его в .gitignore — он уже в истории коммитов. Без перезаписи истории секрет не «спрятать».

  4. Логи пайплайнов CI/CD. Скрипты сборки постоянно работают с секретами, чтобы задеплоить приложение. Ошибка в bash-скрипте вроде echo $SECRETS_JSON или падение пайплайна с подробным трейсбеком могут распечатать ключи прямо в логи GitLab CI или Jenkins, доступ к которым часто есть у широкого круга сотрудников.

  5. Мессенджеры и таск-трекеры. «Скинь пароль от тестовой БД» — «Держи: ...» Знакомо? Довольно часто секреты пересылаются в мессенджерах. И если аккаунт одного сотрудника когда-нибудь скомпрометируют, вся эта коллекция становится золотой жилой для атакующего.

  6. Docker-образы. Частая ошибка при сборке: копирование конфигурационных файлов вместе с секретами внутрь образа инструкцией COPY . .. Даже если контейнер удалит файл на старте в следующем слое, секрет навсегда останется в истории слоёв Docker-образа. С образами ситуация похожа на хардкод, только вместо фрагментов и версий кода мы имеем слоёный пирог, который содержит «слепки» состояний образа во время его сборки, где и могут задерживаться секреты. Например, скопировали .env на слое № 3, удалили на слое № 4 — он всё равно лежит в слое № 3.

Помимо этих «классических» сценариев, с ростом участия ИИ в разработке секреты начинают утекать способами, о которых пару лет назад никто бы не подумал:

  • Prompt Injection. Атака, с помощью которой мы можем вынудить агента прочитать свою память и достать оттуда секрет.

  • Cross-Tenant Memory Leakage (утечка между пользователями). Похожий по смыслу на вариант выше способ потерять секрет. В RAG-системах, где ИИ отвечает на вопросы, опираясь на базу знаний компании, один пользователь может «вытянуть» данные другого. Секреты, попавшие в документы или контекст одного сотрудника, оказываются доступны второму через общий поиск по базе.

  • Multi-Agent Tool Use & Shared State (общая память у нескольких агентов). Представьте двух агентов: один общается с пользователем, второй работает с чувствительными данными. У них общая память. Агент, который «болтает» с человеком, может случайно «проболтаться» или по хитрому запросу со стороны человека выдать секреты из той части, где работают с чувствительными данными. 

  • Конфигурации MCP (Model Context Protocol). Это протокол, по которому ИИ-агенты обмениваются ресурсами и инструментами. Файлы конфигураций контекста (например, mcp.json) часто сохраняют токены доступа к сервисам прямо в структуры памяти / локальных конфигов агента. Когда агенты общаются через общие серверы или прокси, эти токены могут автоматически подмешиваться в запросы вовне или контекст ответов для других пользователей системы. 

Разработчики обычно пишут в инструкциях к своим моделям: «Не смотри в .env-файлы» или «Игнорируй папку config». Но запрет в промпте — это не технический барьер, а просьба. А языковые модели вероятностны по своей природе: они следуют таким просьбам не всегда, а «почти всегда». 99 % времени модель ведёт себя образцово — пока один злополучный промпт или переполнение контекста не заставит её забыть о запретах. И вот тогда секрет оказывается на свободе.

Что будет, если всё-таки утечёт?

Ну утекли и утекли, в чём проблема-то? Отзовём токен, перевыпустим новый, удалим пароль из репозитория (не редактируя дерево коммитов). Однако злоумышленники автоматизируют весь цикл атаки и знают, что инцидент рано или поздно заметят, поэтому нужно успеть в уходящий поезд. 

Яркий пример — инцидент с Trivy в марте 2026 года: злоумышленники использовали украденные CI/CD-секреты, чтобы за несколько часов опубликовать вредоносные релизы популярного сканера уязвимостей во все основные реестры. Тысячи пайплайнов автоматически подтянули малварь раньше, чем команда успела отреагировать. 

К тому моменту, когда вы обнаружите утечку и побежите отзывать ключ, атакующий уже закрепился внутри: поднял бэкдоры, создал новые аккаунты, скопировал данные. Поэтому чаще всего утечка секрета — это не то, с чем можно справиться «после».

К чему это приводит на практике? Последствия утечек можно разделить на три категории: деньги, данные, смерть бизнеса. Разберём по порядку.

Финансовый ущерб и захват инфраструктуры

Злоумышленники мониторят публичные репозитории 24/7. Утекший токен AWS или Yandex Cloud парсится ботами в среднем за 2–3 минуты. Именно так происходит большинство захватов инфраструктуры. Получив ваш API-токен, автоматика мгновенно закрепляется внутри: поднимает инстансы, создаёт новые сервисные аккаунты, меняет политики доступа. К моменту, когда вы заметите странное в биллинге, отзывать токен будет уже поздно — у атакующего есть собственные ключи. Дальше — шантаж, продажа доступа или просто счёт на миллионы.

Но это ещё не всё. Современные группировки вымогателей больше не просто шифруют диски, а целенаправленно охотятся за секретами в GitLab/GitHub и облаках. В 2025–2026 годах группировка Crimson Collective атаковала компании (как в случае с GitLab Red Hat или базами данных провайдера Brightspeed) через утекшие токены и конфиги: получив доступ к внутреннему GitLab или базам данных, они скачивали терабайты данных и шантажировали жертв публичным сливом.

Утечки данных и юридические последствия

Четыре показательные истории последних лет:

  • Кейс Toyota (2022). Выяснилось, что ключ доступа к серверу данных Toyota лежал в публичном репозитории на GitHub почти 5 лет! Разработчик-субподрядчик случайно залил туда кусок кода. Потенциально были скомпрометированы данные около 300 000 клиентов.

  • Кейс «Яндекса» (2023). В свободный доступ попал дамп внутренних Git-репозиториев компании объёмом 44,7 ГБ. По результатам расследования выяснилось, что в коде содержались захардкоженные секреты, сервисные ключи и тестовые креды. А причиной стало нарушение внутренних ИБ-политик при работе с кодом. Наглядный пример того, почему даже наглухо закрытый внутренний монорепозиторий нельзя считать безопасным местом для хранения секретов.

  • Атаки на Supply Chain и цепочки доверия (кейсы Trivy, LiteLLM, Checkmarx) (2026). В 2026 году секреты начали утекать не только из вашего кода, но и из инструментов, которым вы доверяете. Когда компрометируется токен популярной библиотеки или DevSecOps-сканера, под ударом оказываются не отдельные разработчики, а сотни компаний, использующих эти инструменты в своих CI/CD-пайплайнах. Один скомпрометированный секрет превращается в атаку на всю цепочку поставок (Supply Chain). Так произошло со сканером уязвимостей Trivy, прослойкой для работы с LLM LiteLLM и компонентами Checkmarx: злоумышленники получали токены на публикацию, внедряли малварь в очередные релизы, и тысячи пайплайнов автоматически подтягивали заражённые версии.

  • ChainDrop (2026). В августе 2026 года исследователи из Unit 42 описали червя ChainDrop, который заразил сотни npm-пакетов. Червь дампил память CI-раннеров GitHub Actions, крал npm-токены и автоматизированно перепубликовал заражённые версии популярных библиотек.

  • ИИ-бум и новые риски (2025–2026). Спешка в гонке ИИ-технологий сделала секреты ещё уязвимее. Исследование Wiz показало, что 65 % компании из Forbes AI 50 случайным образом выложили в публичный доступ ключи доступа и токены. А массовый переход на вайб-кодинг и ИИ-ассистенты только подлил масла в огонь: разработчики всё чаще коммитят сгенерированные нейросетью конфигурационные файлы (вроде mcp.json или .env) с захардкоженными ключами от OpenAI, Hugging Face и облачной инфраструктуры. 

Если в утечке оказались персональные данные клиентов, подключаются два ключевых закона. ФЗ-152 «О персональных данных» требует защищать ПДн и уведомлять Роскомнадзор об утечках. А ФЗ-149 «Об информации, информационных технологиях и о защите информации» регулирует общие требования к защите информации и меры против утечек. Плюс обязанность уведомить пострадавших пользователей и провести внутреннее расследование. Один забытый токен — и вот вам не только технический инцидент, но многомиллионные штрафы, суды и репутационный ущерб.

Полное уничтожение бизнеса

Штрафы и суды — это ещё полбеды. Бывает, что после утечки бизнес просто перестаёт существовать.

  • Кейс Code Spaces (2014). Сервис хостинга кода Code Spaces столкнулся с тем, что атакующий получил доступ к их облачной панели через украденные ключи и потребовал выкуп. Ему отказали. Тогда он просто нажал «Удалить всё»: базы данных, бэкапы, виртуальные машины. Процветающий бизнес был уничтожен за один день.

Причины ошибок и как с ними работать

Почему, зная о таких рисках, мы продолжаем допускать утечки? Причина — Time to Market. Бизнес требует фич, разработчики торопятся. Иногда это банальная халатность. А с приходом ИИ скорость разработки и поставки увеличивается, иногда на порядки. Однако количество внимания человека остаётся неизменным, что усугубляет ситуацию с потенциальными утечками.

К тому же существует ложное чувство безопасности: «Это же наш закрытый on-premise GitLab, кто тут этот ключ найдёт?» Но внутренние репозитории текут так же часто — через обиженных уволенных сотрудников, скомпрометированные VPN-доступы или взломанные ноутбуки.

Что можно сделать прямо сейчас, чтобы убедиться, что у вас нет секретов в коде? Начать с очевидного:

  1. Проверяем .gitignore. Убедитесь, что конфигурационные файлы и окружения (.env, .env.local, *.pem, id_rsa, *.key, mcp.json) внесены в исключения до первого коммита. 

  2. По-grep-ать Git. Для быстрой проверки локального репозитория можно использовать git + grep: git log -p | grep -E -i "(pypi-|ghp_|aws_secret|password\s*=)" 

  3. Использовать инструмент злоумышленника: docker run --rm -v $(pwd):/path zricethezav/gitleaks:latest detect --source="/path" -v 

Нашли секрет?

Не паникуйте! Используйте следующий алгоритм:

  1. Ротируйте секрет. Отзовите ключ или токен, выпустите новый и замените его в местах, где он использовался.

  2. Удалите его из истории. Недостаточно будет удалить секрет из кода и запушить правку — нужно удалить его из истории. Для этого можно редактировать дерево вручную либо использовать git-filter-repo или BFG Repo-Cleaner. И проверьте, что в самом последнем коммите не содержится секрет, поскольку инструменты часто не трогают его, чтобы не убить продуктовую развёртку.

  3. Уведомите ответственных. К любой потенциальной утечке лучше отнестись как к реализованному риску: считайте, что секрет уже побывал в чужих руках.

Надеяться на внимательность при код-ревью бессмысленно — глаза замыливаются. Процесс поиска утекающих секретов необходимо автоматизировать. А те, которые не утекают, должны правильно обрабатываться. В корпоративной среде эту задачу закрывают решения класса DLP (Data Loss Prevention) и SM (Secret Management).

В контексте разработки это означает:

  • автоматизированный анализ кода (SAST) и сканирование истории коммитов;

  • интеграцию проверок в CI/CD-пайплайны — чтобы секрет не доехал до продакшена;

  • отлов секретов через pre-commit-хуки до попадания в репозиторий;

  • хранение, передачу и ротацию секретов защищённым способом.

А что дальше?

Как именно выстроить такой процесс, встроить проверки в продукт и не сойти с ума от ложных срабатываний? Если вам это болит и вы хотите, чтобы мы рассказали об этом в следующих статьях, — напишите в комментариях. О чём именно: про инструменты, про процесс внедрения, про конкретные кейсы?

И читайте наши статьи, чтобы мы не читали о вас в новостях!

Что ещё почитать в наших блогах:

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.