Klucze API i hasła w repozytorium Git: jak ich nie wypuścić

Sekret, który raz trafił do commita, zostaje w historii Git nawet po usunięciu pliku. Dlatego trzymaj klucze poza kodem, w zmiennych środowiskowych lub menedżerze sekretów, a plik .env dopisz do .gitignore. Gdy klucz już wyciekł, najpierw go unieważnij, a dopiero potem czyść historię narzędziem git-filter-repo.

Opracowanie z użyciem narzędzi AI, na podstawie źródeł pierwotnych

Papierowy klucz wysuwający się spomiędzy teczek z dokumentami, kolaż z papieru

Klucz API wklejony na chwilę do kodu, plik .env dodany przez git add ., hasło do bazy w pliku konfiguracyjnym. Tak zaczyna się większość wycieków sekretów z repozytoriów. Według raportu GitGuardian z marca 2026, firmy, która sprzedaje narzędzia do wykrywania sekretów, w publicznych commitach na GitHubie w 2025 roku znalazło się 28,65 mln sekretów, o 34% więcej niż rok wcześniej. Ten poradnik pokazuje, jak temu zapobiec i co zrobić, gdy już się stało.

1. Dlaczego usunięcie pliku nie wystarcza

Git zapisuje historię projektu jako serię migawek. Commit, który usuwa plik z hasłem, dodaje tylko nową migawkę bez tego pliku. Poprzednie commity nadal go zawierają, a każdy, kto sklonuje repozytorium, dostaje całą historię.

W repozytorium publicznym oznacza to, że sekret trzeba uznać za ujawniony od chwili wypchnięcia. Raport GitGuardian podaje też, że 64% sekretów, które były ważne w 2022 roku, nadal działało w styczniu 2026. Wyciek bez unieważnienia klucza pozostaje więc zagrożeniem przez lata.

2. Trzymaj sekrety poza kodem

Zasada The Twelve-Factor App mówi, że konfiguracja, w tym dane dostępowe, powinna być przechowywana w zmiennych środowiskowych, a nie w kodzie. Kod ma dać się opublikować bez ujawniania żadnych danych uwierzytelniających. OWASP zaleca dodatkowo centralny menedżer sekretów, regularną rotację kluczy i przydzielanie im możliwie wąskich uprawnień.

W małych projektach sekrety trzyma się zwykle w pliku .env, który aplikacja wczytuje przy starcie. Taki plik musi zostać wyłącznie na twoim komputerze albo serwerze. Do repozytorium dodaj za to plik .env.example z samymi nazwami zmiennych, bez wartości.

3. .gitignore i pliki już śledzone

Plik .gitignore mówi Gitowi, których plików nie śledzić. Szablon dla Node.js z repozytorium GitHub wyklucza wszystkie pliki .env i .env.*, a dopuszcza .env.example:

.env
.env.*
!.env.example

Dokumentacja Git zastrzega, że .gitignore nie działa na pliki już śledzone. Jeśli .env trafił wcześniej do repozytorium, usuń go z indeksu poleceniem git rm z opcją --cached. Plik zostanie na dysku, ale przestanie być częścią kolejnych commitów. Starsze commity nadal go zawierają, o czym mówią sekcje 7 i 8.

git rm --cached .env
git commit -m "Przestań śledzić plik .env"

4. Automatyczna blokada przed commitem

Człowiek w końcu się pomyli, dlatego warto dodać automatyczną kontrolę przed każdym commitem. Gitleaks skanuje zmiany w poszukiwaniu kluczy i haseł i może działać jako hook frameworka pre-commit. Konfiguracja w pliku .pre-commit-config.yaml wygląda tak:

repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.2
    hooks:
      - id: gitleaks

Hook instalujesz poleceniem pre-commit install, a całe repozytorium sprawdzisz przez pre-commit run --all-files. Wersję w polu rev zaktualizujesz poleceniem pre-commit autoupdate. Fałszywe alarmy oznaczysz komentarzem gitleaks:allow w linii kodu albo plikiem .gitleaksignore.

5. Ochrona po stronie GitHuba

GitHub ma dwa mechanizmy. Secret scanning przeszukuje repozytorium i powiadamia o znalezionych sekretach. Od 15 grudnia 2022 jest bezpłatny dla repozytoriów publicznych. W ramach programu partnerskiego GitHub powiadamia też dostawcę znalezionego klucza, a decyzja o jego unieważnieniu należy do dostawcy.

Push protection działa wcześniej. Blokuje wypchnięcie commita, w którym wykrył sekret. Od 29 lutego 2024 GitHub włączał tę ochronę dla darmowych kont przy wypychaniu do repozytoriów publicznych. Jeśli push zostanie zablokowany, a sekret jest w ostatnim commicie, usuń go z kodu i popraw commit poleceniem git commit --amend --all, zanim spróbujesz ponownie.

6. Ochrona w GitLabie

GitLab oferuje secret push protection, który blokuje wypchnięcie zmian zawierających sekrety. Ta funkcja jest dostępna w planie Ultimate. W planach Premium i Ultimate działa też reguła pushów, która blokuje wypychanie typowych plików z sekretami. W darmowym planie rolę pierwszej linii obrony pełni więc hook pre-commit z sekcji 4.

7. Klucz wyciekł: najpierw go unieważnij

GitHub, OWASP i autor git-filter-repo zgadzają się co do kolejności. Najpierw unieważnij albo zmień sekret w panelu dostawcy, na przykład w konsoli chmury albo serwisie płatności. Dopiero potem czyść historię. Przepisanie historii nie usuwa sekretu z cudzych klonów i forków, więc sam klucz musi przestać działać.

Po unieważnieniu sprawdź w logach dostawcy, czy ktoś nie użył klucza w czasie, gdy był ujawniony. Nowy klucz zapisz już poza repozytorium, zgodnie z sekcją 2.

8. Czyszczenie historii narzędziem git-filter-repo

GitHub zaleca git-filter-repo w wersji 2.47 lub nowszej z opcją --sensitive-data-removal. Starsze polecenie git filter-branch sama dokumentacja Git odradza. Plik usuniesz z całej historii tak:

git-filter-repo --sensitive-data-removal --invert-paths --path .env
git push --force --mirror origin

Jeśli sekret był w kodzie, a nie w osobnym pliku, użyj opcji --replace-text z plikiem zawierającym szukane wartości. Domyślnie każde trafienie zostanie zastąpione tekstem ***REMOVED***. Przepisanie historii zmienia identyfikatory commitów, więc każdy współpracownik musi ponownie sklonować repozytorium.

GitHub ostrzega, że nie da się w ten sposób oczyścić forków ani klonów innych osób. Pull requesty i widoki w pamięci podręcznej mogą wymagać zgłoszenia do GitHub Support. Listę pull requestów, których dotknęło przepisanie, git-filter-repo zapisuje w katalogu .git/filter-repo/.

9. Podsumowanie

Sekretów nie da się bezpiecznie usunąć z historii Git po fakcie, więc liczy się zapobieganie. Trzymaj je w zmiennych środowiskowych albo menedżerze sekretów, dopisz .env do .gitignore i dodaj hook z Gitleaks. Na GitHubie korzystaj z push protection. Gdy mimo to klucz wycieknie, najpierw go unieważnij, a dopiero potem przepisz historię.

Najczęstsze pytania

Czy usunięcie pliku z hasłem w nowym commicie wystarczy?

Nie. Git zapisuje każdą wersję projektu jako migawkę, więc plik nadal jest w starszych commitach i każdy, kto sklonuje repozytorium, może go odczytać. Sekret trzeba unieważnić, a historię przepisać.

Dlaczego .gitignore nie działa na mój plik .env?

Dokumentacja Git wyjaśnia, że .gitignore nie dotyczy plików już śledzonych. Jeśli plik trafił wcześniej do repozytorium, usuń go z indeksu poleceniem git rm --cached, a potem dopisz do .gitignore.

Czy wyczyszczenie historii usuwa sekret z GitHuba na dobre?

Nie zawsze. GitHub ostrzega, że nie da się oczyścić forków ani klonów zrobionych przez innych. Pull requesty i widoki w pamięci podręcznej mogą wymagać zgłoszenia do GitHub Support. Dlatego unieważnienie sekretu jest ważniejsze niż czyszczenie historii.

Źródła

  1. gitignore Documentation, Git
  2. git-rm Documentation, Git
  3. Pro Git, What is Git?, Git
  4. Removing sensitive data from a repository, GitHub
  5. About secret scanning, GitHub
  6. About push protection, GitHub
  7. Push protection is enabled for free users on GitHub, GitHub (2024)
  8. Secret scanning is now available for free on public repositories, GitHub (2022)
  9. git-filter-repo, Elijah Newren
  10. Secret push protection, GitLab
  11. Secrets Management Cheat Sheet, OWASP
  12. The Twelve-Factor App: III. Config, The Twelve-Factor App
  13. Gitleaks, Gitleaks (2026)
  14. The State of Secrets Sprawl 2026, GitGuardian (2026)

O autorze

Rafał Lesiński na co dzień zajmuje się administracją systemów i wsparciem IT dla małych firm. Pracuje z serwerami Linux (Debian, Ubuntu Server) i Windows Server, platformą Microsoft Azure oraz usługami Microsoft 365, w tym Entra ID, Teams i SharePoint Online. Zajmuje się też monitoringiem i bezpieczeństwem infrastruktury (Zabbix, Wazuh, Microsoft Sentinel) oraz wirtualizacją i automatyzacją (Proxmox VE, Hyper-V, Docker, Ansible). Programuje w Pythonie i PHP (Laravel). Prowadzi serwis Wybryki Informatyki, w którym każdy artykuł opiera się na dokumentacji i źródłach pierwotnych.

Niezbędne (zawsze włączone). Pamięć przeglądarki przechowuje wybrany motyw, polubione artykuły i Twoją decyzję o zgodzie. Nie używamy do tego plików cookies.