Случайный комит секретной информации в git

Когда мы разрабатывали Connekt — наш HTTP Client — один из вопросов, который встал перед нами: как правильно работать с секретами? API-ключи, токены, пароли — разработчики постоянно используют их при тестировании API, и важно делать это безопасно.

Мы изучили существующие подходы в индустрии и обнаружили интересные паттерны — как удачные, так и проблемные.

Анатомия утечки: как секрет попадает в публичный доступ?

Большинство утечек секретов следует одному и тому же сценарию. Представьте типичный день разработчика:

Шаг 1: Создание
Понедельник, 10:00. Разработчик добавляет API-ключ в Postman environment для тестирования нового эндпоинта. Файл сохраняется на диске в plain text — это как хранить ключи от квартиры под ковриком. Но ведь это локально, так можно, всё под контролем, что может пойти не так?

{
  "production": {
    "API_KEY": "sk_live_51H...",
    "DB_PASSWORD": "super_secret_pass"
  }
}

Шаг 2: Синхронизация
Инструмент автоматически синхронизирует коллекцию в облако для удобства работы с других устройств. Теперь секрет существует в двух местах: на локальном диске и на сервере в облаке.

Шаг 3: Шеринг
Вторник, 14:30. Коллега просит поделиться коллекцией для воспроизведения бага. Разработчик экспортирует JSON-файл и отправляет через Teams/Slack/Mattermost или что там у вас используют. Секрет теперь в третьем месте.

Шаг 4: Version Control
Среда, 16:00. Коллега добавляет полученную коллекцию в проект и коммитит в Git для удобства команды. Git сохраняет файл в истории навсегда. Удалить секрет из истории Git — нетривиальная задача, которую мало кто делает правильно.

Шаг 5: Случайный коммит
Пятница, 18:45. Разработчик спешит закоммитить фичу перед выходными. В IDE открыто много файлов, он быстро кликает "Commit All" и не замечает, что в список попал .postman_environment.json. Или забыл снять галочку с этого файла при коммите или не добавил в .gitignore. В конечном итоге, файл уходит в публичный репозиторий. Игра окончена — секрет в публичном доступе.

Реальный пример: инцидент Uber (2022)

Хакер получил доступ к корпоративному Slack, где в одном из каналов нашёл Postman-коллекцию с AWS credentials. Используя эти credentials, злоумышленник украл 77GB данных, включая информацию о 57 миллионах пользователей и водителей.

Последствия:

  • Штраф от регуляторов — $148 миллионов

  • Ущерб репутации компании

  • Массовые увольнения в security-команде

  • Обязательный пересмотр всех security практик

Что пошло не так:

  1. Секреты хранились в plain text в Postman-коллекции

  2. Коллекция была расшарена в Slack канале (доступ у сотен сотрудников)

  3. Никто не ротировал credentials после утечки

  4. Отсутствовал мониторинг использования критических API-ключей

Это не единичный случай:

  • 2024, RedHunt Labs Project Resonance (Wave 14): Годовое исследование публичных Postman-коллекций выявило массовые утечки секретов из 200,000+ окружений. Обнаружено 70,000 JWT-токенов, 5,500 Bearer-токенов, 2,000+ Postman API ключей, а также credentials для AWS, GitHub, Azure, OpenAI и других сервисов. В одном из кейсов утечка AWS-ключей дала доступ к CloudWatch логам и инфраструктуре UK-стартапа. (RedHunt Labs Research)

  • 2023, CircleCI incident: Компрометация привела к утечке environment variables и secrets клиентов. Пострадало более 4,500 организаций, потенциальный ущерб превысил $100 миллионов (CircleCI Security Alert)

  • 2022, Heroku & Travis CI OAuth Token Theft: Компрометация OAuth tokens через GitHub привела к доступу к credentials и secrets в CI/CD системах. Атакующие получили доступ к приватным репозиториям и environment variables множества разработчиков (GitHub Security Alert)

  • 2021, Codecov Supply Chain Attack: Взлом CI/CD привел к краже environment переменных, включая Postman API ключи у сотен компаний. Ущерб для одной только Twilio составил несколько миллионов долларов (Codecov Incident Report)

  • 2020, SolarWinds: Частью масштабной атаки стала компрометация Postman-коллекций, отправленных подрядчикам через email. Доступ к системам 18,000+ организаций, включая правительственные агентства США (CISA Alert)

Почему так происходит: системные проблемы инструментов

Postman: удобство против безопасности

Postman — самый популярный HTTP-клиент, но его подход к безопасности создаёт риски.

Проблема 1: Экспорт коллекций — секреты попадают в Git в plaintext

В некоторых случаях Postman collections и environment файлы синхронизируются или экспортируются и хранятся в публичных репозиториях вроде GitHub. Если чувствительные данные не замаскированы или не очищены перед загрузкой, они становятся доступны любому с доступом к репозиторию.

При экспорте из Postman:

  • Collection — экспортируются Shared collection variables как plain text

  • EnvironmentShared variables экспортируются в plaintext, Mark as sensitive экспортирует пустое значение.

Проблемы:

  • Чтобы использовать переменные в CI/CD через Newman, разработчики часто делают их Shared — и они экспортируются в plaintext

  • Postman не предупреждает при экспорте что файл содержит секреты. Предупреждает только когда делаешь переменную Mark as sensitive + Shared

  • Секреты остаются в истории Git даже после удаления файла

Проблема 2: Форки коллекций

Механизм форков позволяет копировать популярные коллекции и подставлять свои ключи для тестирования. Если workspace публичный — ключи видны всем.

Сканирование 40,000 workspace показало следующую статистику:

  • 16% публичных форков коллекции OpenAI содержали живые credentials

  • 20% форков Pynt (инструмент безопасности API) содержали активные API-ключи

Проблема 3: Vault строго локальный — нельзя шарить с командой

Postman Local Vault — храните чувствительные данные как vault secrets в вашем локальном экземпляре Postman. Только вы можете получить доступ к vault secrets в вашем Postman Local Vault, и они не синхронизируются в облако Postman.

Проблемы:

  • Если у команды 10 человек, каждый должен вручную добавить секреты в свой локальный vault.

  • В CI/CD (Newman, Postman CLI) vault secrets просто не существуют — pipeline их не видит.

IntelliJ IDEA HTTP Client: локальность — не панацея

IDEA HTTP Client, который встроен во все IDE от JetBrains, избегает облачной синхронизации, но имеет свои проблемы:

Проблема 1: Plain text без защиты

// http-client.env.json
{
  "production": {
    "API_KEY": "sk_live_actual_secret_key",
    "DB_PASSWORD": "super_secret_password"
  }
}

http-client.env.json файл лежит в проекте рядом с .http файлами и легко попадает в Git при невнимательности.

Проблема 2: Нет автоматического .gitignore

IDEA не создаёт .gitignore для environment файлов автоматически. Не предупреждает при попытке закоммитить файл с потенциальными секретами. Нет защиты от дурака — легко случайно забыть снять галочку при коммите.

Проблема 3: Private environment требует знания о фиче

IDEA предлагает http-client.private.env.json, который IDE не индексирует. Звучит хорошо, но на практике:

  • Нет автоматического .gitignore — ничто не мешает добавить файл в Git вручную, например, случайно

  • Нет проверки при коммите — можно случайно запушить

Как эти проблемы решает Connekt

В Connekt мы реализовали Private Environment (PR #12) с тремя ключевыми особенностями:

1. Автоматический .gitignore при создании

Когда вы создаёте private environment, Connekt:

  • Проверяет наличие .gitignore в корне проекта

  • Если файла нет — создаёт его

  • Добавляет connekt.private.env.json в ignore-лист

Результат: закоммитить секреты становиться значительно сложнее.

2. Разделение публичной конфигурации и секретов

Примечание: IDEA HTTP Client также поддерживает разделение через http-client.private.env.json, но требует знания о фиче. В Postman такого разделения нет — все переменные в одном файле.

// connekt.env.json (публичная конфигурация, можно коммитить в Git)
{
  "production": {
    "apiUrl": "https://api.example.com",
    "timeout": "5000",
    "debugMode": "false"
  }
}


// connekt.private.env.json (секреты, автоматически в .gitignore)
{
  "production": {
    "apiKey": "sk_live_actual_secret_key",
    "dbPassword": "super_secret_password"
  }
}

Connekt автоматически мержит переменные из обоих файлов. Если переменная присутствует в обоих файлах, приоритет у private environment.

Так же есть предупреждение о том что файл connekt.private.env.json не зарегестрирован в gitignore и предложение его туда добавить.

3. Работает из коробки

Не нужно вручную добавлять записи в .gitignore

Просто создаёте private environment через UI — остальное Connekt делает сам.

Connekt файл > Создать приватную конфигурацию для Connekt файла
Connekt файл > Создать приватную конфигурацию для Connekt файла

Сравнение решений

Возможность

Postman

IDEA HTTP Client

Connekt

Автоматический .gitignore

Нет

Нет

Да

Локальное хранение по умолчанию

Облако

Локально

Локально

Разделение публичной и приватной конфигураций

Вручную

Нужно знать о фиче

Автоматически

Защита от случайного экспорта приватной конфигураций

Не применимо

Нет

Да

Предупреждения о рисках

Частично

Нет

Да

Что дальше?

Private Environment решает большинство проблем для индивидуальных разработчиков и небольших команд. Для enterprise-сценариев мы рассматриваем возможность интеграции с:

  1. SOPS (Secrets OPerationS) — индустриальный стандарт для шифрования секретов с поддержкой корпоративных KMS.

    Преимущества:

    1. Шифрование с использованием AWS KMS, GCP Cloud KMS, Azure Key Vault, PGP

    2. Git-friendly: можно безопасно коммитить зашифрованные секреты

    3. Централизованное управление доступом через IAM policies

    # connekt.private.env.sops.yaml (можно коммитить!)
    production:
      apiKey: ENC[AES256_GCM,data:8fH7gK...,iv:...,tag:...]
    dbPassword: ENC[AES256_GCM,data:mN9pQ...,iv:...,tag:...]
    
  2. Возможно интеграция с HashiCorp Vault – для команд, использующих Vault:

    {
      "production": {
        "apiKey": "vault://secret/data/api#key",
        "dbPassword": "vault://secret/data/db#password"
      }
    }
    

    Connekt будет автоматически получать секреты из Vault при выполнении запросов.

Есть что добавить? Сталкивались с утечками секретов? Есть идеи по улучшению безопасности HTTP-клиентов? Интересует ли вас SOPS или HashiCorp Vault в контексте Connekt? Поделитесь этим в комментариях или в нашем Телеграм-чате.


Попробуйте Connekt, если для вас важна безопасность API-ключей. Проект доступен на GitHub, там же можно оставлять issues и предложения. Также прочитайте обзор Connekt на Хабр от Домклик: https://habr.com/ru/companies/domclick/articles/965116/.

Комментарии (10)


  1. albalyu
    02.02.2026 09:15

    Реклама, такая реклама...

    Шаг 1: Создание

    Понедельник, 10:00. Разработчик добавляет API-ключ в Postman environment для тестирования нового эндпоинта. Файл сохраняется на диске в plain text — это как хранить ключи от квартиры под ковриком. Но ведь это локально, так можно, всё под контролем, что может пойти не так?

    Ни разу за всю мою многолетнюю практику написания кода не имел необходимости писать эндпоинты с параметрами API_KEY и DB_PASSWORD . Ни один нормальный разработчик так делать не будет. А если кому-то придет на ум, то на код ревью получит по шапке и пойдет на ковер к начальству. Или Вы эти данные храните на клиенте?... Очень сильно притянуто за уши.

    Шаг 3: Шеринг

    Вторник, 14:30. Коллега просит поделиться коллекцией для воспроизведения бага. Разработчик экспортирует JSON-файл и отправляет через Teams/Slack/Mattermost или что там у вас используют. Секрет теперь в третьем месте.

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

    Шаг 4: Version Control

    Среда, 16:00. Коллега добавляет полученную коллекцию в проект и коммитит в Git для удобства команды. Git сохраняет файл в истории навсегда. Удалить секрет из истории Git — нетривиальная задача, которую мало кто делает правильно.

    Не проект, а дырявое решето какое-то. На нормальном проекте за такие вещи очень больно бъют по шапке, вплоть до штрафов и увольнения. Да и после дискредитации секретов, кто может помешать их обновить и удалить файл из отслеживания git-ом, что снова относится к требованим безопасности.

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

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

    А в начале статьи надо писать большими буквами: РЕКЛАМА.


    1. alexander-shustanov
      02.02.2026 09:15

      Ни разу за всю мою многолетнюю практику написания кода не имел необходимости писать эндпоинты с параметрами API_KEY и DB_PASSWORD . Ни один нормальный разработчик так делать не будет. А если кому-то придет на ум, то на код ревью получит по шапке и пойдет на ковер к начальству. Или Вы эти данные храните на клиенте?... Очень сильно притянуто за уши.

      а как ключ передавать еще? вот за примером далеко ходить не надо, google gemini api: https://ai.google.dev/api#authentication

      Да и практически любой api принимает ключ в хедере. по поводу DB_PASSWORD - согласен, странно выглядит.

      Но опять-таки, на тех проектах которые я знаю, это никто не будет делать через общие чаты - ибо нарушение требований безопасности. И после скачивания эти данные сразу удаляются из чата. Если они остались там висеть - опять нарушение требований безопасности.

      так и есть, но вот знаете, большинство разработчиков, как будто, этими правилами пренебрегает. Недавно вот статью писали, выяснили, что разработчики не видят ничего плохого в кряках, которые выполняют весьма сомнительные операции.

      А в начале статьи надо писать большими буквами: РЕКЛАМА.

      А вы что ожидаете увидеть в корпоративном блоге? Все корпоративные блоги для этого и существуют, кто-то HR бренд продвигает, кто-то свои продукты. Мы стараемся делать это интересно. Жаль, если вам так не показалось.


    1. honest_niceman
      02.02.2026 09:15

      на тех проектах которые я знаю

      В статье приведены ссылки на отчеты по кибер-безопасности. Если вам доводилось работать в компаниях и командах, которые не допускали подобных ошибок – это прекрасно, что тут ещё сказать?)

      ни разу за всю мою многолетнюю практику написания кода не имел необходимости писать эндпоинты с параметрами API_KEY и DB_PASSWORD

      Насколько я понял, в статье речь в целом про эндпоинты с авторизацией. У вас все эндпоинты были без авторизации?

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

      Postman хорош, этого никто не отрицает. Вы, кстати, попробуйте Connekt, а то сразу "не очень хороший". Практически всем, с кем я общался, он пришелся по душе. Есть, конечно, косяки, но мы над ними работаем. Вот кстати, статья ребят из Домклик, которую мы не просили писать: https://habr.com/ru/companies/domclick/articles/965116/ Возможно, не такой уж и "не очень хороший" получился, раз пробуют и рассказывают об этом :)

      на непонятно что от неизвестно кого.

      Конечно, до уровня популярности Postman нам, пока что, далеко. Но мы давно занимаемся разработкой инструментов для других разработчиков: JPA Buddy (6+млн скачиваний), React Buddy (800к скачиваний), Amplicode, Jmix, OpenIDE. В общем, известны в узких кругах и верим в своё дело)

      А в начале статьи надо писать большими буквами: РЕКЛАМА.

      Но ведь тогда никто читать не будет, а чтобы прочитали, мы не просто говорим "смотрите вот такую фичу добавили", а рассказываем, почему в принципе мы решили эту фичу запилить, какие были предпосылки, как заявленную проблему решают другие инструменты и т.д. Мне видится такой формат более интересным и практичным.


      1. albalyu
        02.02.2026 09:15

        Насколько я понял, в статье речь в целом про эндпоинты с авторизацией. У вас все эндпоинты были без авторизации?

        Это Вы так поняли. А я понял, что это эндпоинты с параметрами API_KEY и DB_PASSWORD. Если бы речь шла просто об авторизации, то да, я согласен. Но просто авторизация это же не так интересно. Куда интереснее будет DB_PASSWORD. А еще лучше, если от продовской базы, на что статья и намекает (судя по названию, говорит открытым текстом). Видимо для того, чтобы произвести большее впечатление.


  1. albalyu
    02.02.2026 09:15

    а как ключ передавать еще? вот за примером далеко ходить не надо, google gemini api: https://ai.google.dev/api#authentication

    А Вы собрались с какой-то целью тестировать google gemini api с помощью Postman? Зачем? У них есть документация. Хотите узнать какие-то недокументированные возможности?

    Если вы собираетесь слать туда запросы, то они должны идти с Вашего сервера, а не с клиента. И в эндпоинтах к Вашему API эти ключи не нужны. Они должны храниться где-то в конфигах развернутого инстанса, на сервере Если они шлются с клиента, то это огромная дыра размером с дом.

    А вы что ожидаете увидеть в корпоративном блоге? Все корпоративные блоги для этого и существуют, кто-то HR бренд продвигает, кто-то свои продукты. Мы стараемся делать это интересно. Жаль, если вам так не показалось.

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

    Вот только с моей точки зрения, крайне искусственные примеры, использующиеся для нападения на сторонний продукт с целью возвышения Вашего, это совсем не интересно. Идея у Вашего продукта может и интересная, но после такой рекламы от Вас у меня нет никакого желания его рассматривать ни в каком качестве.


    1. alexander-shustanov
      02.02.2026 09:15

      А Вы собрались с какой-то целью тестировать google gemini api с помощью Postman? Зачем? У них есть документация. 

      Вы мне запрещаете слать запросы на Google Gemini API как мне вздумается?) Вообще при любом кейсе интеграции внешнего API очень удобно сначала этот путь пройти с помощью инструмента типа Connekt или того же Postman. А потом закодить. Это просто сильно быстрее, чем кодить, запускать, смотреть где упало, опять кодить. Написал скрипт, в процессе отладил, никакой инфраструктуры он дополнительно не поднимает, каждая итерация максимально короткая.

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

      Я подозреваю, что вы не до конца поняли, зачем нужен наш инструмент. Запросы будут идти именно с сервера. Но перед тем, как этот код я запрогаю на сервере, я могу накидать скрипт в Connekt.


  1. corporate-sellout
    02.02.2026 09:15

    Без кликбейтных заголовков нельзя свою софтину прорекламировать?


  1. vitiok78
    02.02.2026 09:15

    Bruno - на замену Postman

    Hurl - на замену Jetbrains Http Client

    И всё. Зачем изобретать ещё одну тулзу, которая не решает никаких новых проблем?

    А вообще, Jetbrains уже давно пора допилить интеграцию с .env файлом, которая пока коряво работает, и тогда не надо будет думать какую бы мне ещё внешнюю зависимость добавить в мой проект, ведь я ещё пока очень мало страдаю от внешних зависимостей, а это непорядок!


    1. alexander-shustanov
      02.02.2026 09:15

      Слушайте, hurl это ужасно, ну правда. Когда мы решали, разрабатывать СonneKt или нет, мы его рассматривали. Позволяет немного больше чем curl, инструментальная поддержка ужасная. По крайней мере, на момент полтора года назад.

      Зачем изобретать ещё одну тулзу, которая не решает никаких новых проблем?

      Проблемы действительно старые, но решение имхо справляется с ними на порядок лучше. Воспользуюсь слабым полемическим приемом и сошлюсь на авторитета: предлагаю посмотреть наш совместный стрим с Романом Елизаровом. https://www.youtube.com/watch?v=BBN3cjsmr8c Постарались рассказать о всех преимуществах


  1. kesn
    02.02.2026 09:15

    Я бы добавил какой-нибудь алерт или варнинг, если в не-секретном файле встречается переменная, содержащая "KEY" или "TOKEN"