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

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
- gitignore Documentation, Git
- git-rm Documentation, Git
- Pro Git, What is Git?, Git
- Removing sensitive data from a repository, GitHub
- About secret scanning, GitHub
- About push protection, GitHub
- Push protection is enabled for free users on GitHub, GitHub (2024)
- Secret scanning is now available for free on public repositories, GitHub (2022)
- git-filter-repo, Elijah Newren
- Secret push protection, GitLab
- Secrets Management Cheat Sheet, OWASP
- The Twelve-Factor App: III. Config, The Twelve-Factor App
- Gitleaks, Gitleaks (2026)
- The State of Secrets Sprawl 2026, GitGuardian (2026)



