Zabezpieczanie Claude Code przed wyciekiem danych.
Praca z agentem na firmowym kodzie wymaga warstw ochrony. Pokazujemy, co realnie działa, a co jest tylko sugestią dla modelu, i jak złożyć deny rules, sandbox oraz hooki w jedną, niezawodną konfigurację.
Autor: Tomek Wojciechowski · Ostatnia aktualizacja:
Macierz skuteczności warstw zabezpieczeń.
| Warstwa | Typ | Skuteczność |
|---|---|---|
| Instrukcje w CLAUDE.md | Miękka | Niska: model może zignorować |
| .claudeignore / .gitignore | Miękka | Zerowa: pliki ignorowane przez agenta |
| settings.json: deny rules | Twarda | Wysoka, ale znane bypassy |
| Sandbox mode | OS-level | Wysoka (macOS/Linux/WSL2) |
| PreToolUse hooks | Deterministyczna | Najwyższa: exit 2 = twarda blokada |
Uwaga: nie polegaj wyłącznie na deny rules. Udokumentowano bypassy (m.in. system reminders ujawniające zawartość zablokowanych plików oraz niespójne egzekwowanie reguł dla .env). Jedyne niezawodne zabezpieczenie to połączenie: sandbox + deny rules + hooki.
settings.json: twarde blokady odczytu i zapisu.
Blokada jest aplikowana przed wywołaniem narzędzia, więc agent nie widzi zawartości. W hierarchii deny zawsze wygrywa nad allow i ask. Lokalizacje pliku:
| Zakres | Linux / macOS | Windows |
|---|---|---|
| Globalnie | ~/.claude/settings.json | %USERPROFILE%\.claude\settings.json |
| Projekt (współdzielony) | .claude/settings.json | .claude\settings.json |
| Projekt (lokalny) | .claude/settings.local.json | .claude\settings.local.json |
Reguły uniwersalne
{
"permissions": {
"deny": [
"Read(./.env)", "Read(./.env.*)",
"Read(./secrets/**)", "Read(./config/credentials.*)",
"Read(**/*.pem)", "Read(**/*.key)",
"Bash(ping *)", "Bash(nslookup *)"
]
},
"cleanupPeriodDays": 7
} Składnia ścieżek: reguły Read i Edit stosują semantykę gitignore (wzorce względem katalogu projektu). Ścieżkę absolutną podajesz przez podwójny ukośnik na początku, np.Read(//etc/hosts).
Dlaczego blokować ping i nslookup: CVE-2025-55284 pokazał eksfiltrację sekretów przez zapytania DNS, a te komendy bywały auto-zatwierdzane. Deny rules blokują narzędzia agenta, nie blokują sieci, dlatego zawsze dorzuć też blokadę curl i wget.
Reguły specyficzne dla systemu
Na Windows komendy powłoki idą przez osobne narzędzie PowerShell. Włącza się samo, gdy nie masz Git Bash, a na kontach claude.ai i Console działa też obok niego. Bez Git Bash narzędzia Bash w ogóle nie ma, więc reguły Bash(…) niczego tam nie zablokują. PowerShell ma własne reguły PowerShell(…), a reguła napisana na cmdlet obejmuje też jego aliasy (np. iwr):
// Linux / macOS
"Read(~/.ssh/**)", "Read(~/.aws/**)", "Read(~/.kube/**)",
"Bash(curl *)", "Bash(wget *)", "Bash(nc *)"
// Windows (narzedzie PowerShell, a przy Git Bash takze Bash)
"PowerShell(Invoke-WebRequest *)", "PowerShell(Invoke-RestMethod *)",
"PowerShell(curl *)", "Bash(curl *)", "Bash(nc *)" Z tego samego powodu hooki na komendy powłoki rejestruj z matcherem Bash|PowerShell, bo hook tylko na Bash na Windows się nie odpali. Ścieżki w regułach Read i Edit Claude Code sprowadza na Windows do postaci POSIX: C:\Users\alice to /c/Users/alice, więc .env w dowolnym miejscu dysku C blokujesz regułą Read(//c/**/.env).
Izolacja OS-level obejmuje też subprocesy.
Sandbox to najsilniejsza praktyczna ochrona dla komend powłoki: izoluje na poziomie systemu operacyjnego komendy narzędzi Bash, PowerShell i Monitor, łącznie z procesami potomnymi. W testach Anthropic zredukował liczbę monitów o ok. 84%. Działa natywnie na macOS, Linux i WSL2, bez instalowania jakichkolwiek zależności na macOS. Natywny Windows nie jest obsługiwany.
| System | Technologia | Status |
|---|---|---|
| macOS | Seatbelt | Pełne wsparcie (natywnie, nic nie instalujesz) |
| Linux | bubblewrap | Pełne wsparcie |
| WSL2 | bubblewrap | Pełne wsparcie |
| Windows natywny | — | Nieobsługiwany |
Konfiguracja
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"allowUnsandboxedCommands": false,
"failIfUnavailable": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
} Granice izolacji: sandbox dotyczy tylko komend powłoki (Bash, PowerShell, Monitor). Read, Write, Edit i WebFetch są poza nim (rządzi nimi permissions.deny). Domyślnie pozwala też czytać cały komputer, łącznie z poświadczeniami AWS i kluczami SSH (izolacja ogranicza zapis i sieć, ale nie odczyt), a komendy dziedziczą zmienne środowiskowe rodzica razem z sekretami w env. Dlatego dwie flagi z konfiguracji powyżej są obowiązkowe: allowUnsandboxedCommands: false, inaczej agent może sam wyłączyć sandbox, gdy komenda zawiedzie, oraz failIfUnavailable: true, dzięki której Claude Code w ogóle nie wystartuje, gdy sandbox jest niedostępny, zamiast cicho przejść w tryb bez izolacji. Na natywnym Windows używaj WSL2 (sudo apt-get install bubblewrap socat) albo Dockera.
Aktualizacja: od wersji 2.1.285 allowUnsandboxedCommands: false wpisane w ~/.claude/settings.json obowiązuje także wtedy, gdy .claude/settings.json repozytorium ustawia true. Wcześniej ustawienie projektu wygrywało. Ustawione w konfiguracji zarządzanej albo przez --settings robi z sandboxa wymóg administratora: Claude Code ignoruje wtedy wpisy repozytorium, które go luzują, łącznie z excludedCommands.
Blokada poświadczeń: sandbox.credentials
Nie ma wbudowanej listy blokad odczytu, więc ścieżki z sekretami blokujesz jawnie. Od wersji 2.1.187 służy do tego dedykowany blok sandbox.credentials: w files wpisujesz ścieżki do zablokowania odczytu, w envVars zmienne do skasowania, każdy wpis z "mode": "deny". Wpisy deny z różnych zakresów się sumują i żaden zakres nie zdejmie blokady dodanej w innym. To czytelniejsze niż rozrzucanie blokad po filesystem.denyRead czy regułach Read w permissions.deny:
{
"sandbox": {
"credentials": {
"files": [
{ "path": "~/.aws/credentials", "mode": "deny" },
{ "path": "~/.ssh", "mode": "deny" }
],
"envVars": [{ "name": "GITHUB_TOKEN", "mode": "deny" }]
}
}
} Drugi tryb to "mode": "mask" (zmienne od 2.1.199, pliki od 2.1.221). Komenda w sandboxie widzi atrapę zamiast tokenu, a proxy sandboxa wstawia prawdziwą wartość dopiero w żądaniu wychodzącym: do hostów z pola injectHosts albo, gdy go nie podasz, do każdego hosta z network.allowedDomains. Maska wymaga też eksperymentalnego network.tlsTerminate, bo proxy musi widzieć treść żądania. Bez niego sekret nie wycieknie, ale uwierzytelnienie się nie uda. Na macOS zamaskowany plik jest po prostu nieczytelny. Maska pozwala proxy wysłać prawdziwy sekret na wskazane hosty, dlatego Claude Code honoruje ją tylko z ustawień użytkownika, ustawień zarządzanych i flagi --settings. W .claude/settings.json repozytorium jest ignorowana.
Zmienne środowiskowe możesz też strippować globalnie: CLAUDE_CODE_SUBPROCESS_ENV_SCRUB usuwa poświadczenia Anthropic i providerów chmurowych ze wszystkich subprocesów. Szerszy bezpiecznik na odczyt to permissions.blockReadsOutsideWorkingDirectories: true (od 2.1.257): Read, Grep i Glob odmawiają czytania poza katalogami roboczymi w każdym trybie uprawnień, także w bypassPermissions, a komendy w sandboxie tracą odczyt katalogu domowego i innych katalogów z plikami użytkownika (poza kilkoma wyjątkami z dokumentacji).
Warstwa, nie szczelna granica: CVE-2026-55607 (załatany w 2.1.163) pokazał ucieczkę przez pomylenie ścieżek git worktree: worktree nazwany .git pozwalał wykonać kod poza Seatbeltem, i działało nawet w trybie read-only. Trzymaj Claude Code zaktualizowany i nie traktuj sandboxa jako jedynej linii obrony. Przy repozytoriach z niezaufaną treścią dorzuć izolację na poziomie kontenera albo VM.
Skrypt przed każdą operacją wykrywa sekrety, zanim trafią do pliku.
Hook to skrypt powłoki uruchamiany przed wybranymi narzędziami. Kod wyjścia decyduje, co się stanie:
- exit 0: operacja przechodzi normalnie.
- exit 1: błąd hooka (operacja może przejść).
- exit 2: twarda blokada (operacja anulowana, agent widzi komunikat).
Rejestracja hooka skanującego Write i Edit
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/detect-secrets.sh" }
]
}
]
}
} Skrypt skanuje generowaną treść pod kątem wzorców sekretów (klucze AWS, tokeny GitHub, klucze Stripe, hasła, connection stringi). Instalacja:
mkdir -p .claude/hooks
# skopiuj detect-secrets.sh do .claude/hooks/
chmod +x .claude/hooks/detect-secrets.sh Zmienna ${CLAUDE_PROJECT_DIR} wskazuje katalog projektu niezależnie od tego, gdzie agent akurat zrobił cd. Sprawdź pierwsze uruchomienie hooka: przy błędnej ścieżce albo braku prawa wykonania powłoka zwraca kod 127, a Claude Code traktuje to jak błąd nieblokujący. Operacja przechodzi, w transkrypcie pojawia się tylko komunikat o błędzie hooka, a bramka po cichu przestaje działać.
PostToolUse: audit log komend Bash
// Linux — dopisuje kazda komende do logu
"PostToolUse": [{
"matcher": "Bash",
"hooks": [{ "type": "command",
"command": "jq -r '.tool_input.command' >> ~/.claude/command-audit-log.txt" }]
}] Warstwy miękkie, self-audit i checklista projektu.
Instrukcje w CLAUDE.md to warstwa miękka. Agent może je zignorować, więc traktuj je jako pierwszą linię świadomości, nie zabezpieczenie:
## Bezpieczenstwo — sekrety i hasla
- NIGDY nie umieszczaj hasel, tokenow i kluczy w kodzie
- Uzywaj zmiennych srodowiskowych: process.env.SECRET_KEY
- Nie czytaj pliku .env, nie echo-uj sekretow na konsole Plik .env z prawdziwymi sekretami nigdy nie trafia do repozytorium. Commitujesz wersję przykładową z placeholderami:
# .env.example — commituj do repo
DATABASE_URL=postgresql://user:password@localhost/mydb
STRIPE_SECRET_KEY=sk_live_your_key_here
GITHUB_TOKEN=ghp_your_token_here
# .gitignore — zawsze
.env
.env.local
*.pem
*.key Self-audit prompt
Wklej ten prompt, gdy chcesz sprawdzić projekt pod kątem bezpieczeństwa:
Zrob audyt bezpieczenstwa tego projektu. Znajdz i zgłos:
1. Zahardkodowane hasla, klucze API, tokeny w kodzie
2. Sekrety w komentarzach
3. Slabe hasla (mniej niz 12 znakow, slowa ze slownika)
4. Pliki .env przypadkiem zacommitowane (sprawdz historie git)
5. Connection stringi z osadzonymi danymi logowania
6. Klucze prywatne i certyfikaty w repozytorium
7. Dane wrazliwe w logach
Dla kazdego znaleziska: plik, numer linii, waga, rekomendacja.
NIE wypisuj prawdziwych wartosci sekretow — tylko wskaz ich obecnosc. Gdy kod nie może wyjść poza firmową chmurę
Claude Code nie musi łączyć się z API Anthropic. Może korzystać z modeli na firmowym koncie w Amazon Bedrock, Agent Platform w Google Cloud (dawniej Vertex AI) albo Microsoft Foundry. U tych dostawców telemetria, raporty błędów i komenda /feedback są domyślnie wyłączone. Włączone zostają ankiety jakości sesji (wyłączysz je zmienną CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY=1) oraz sprawdzanie domen przed WebFetch, które wysyła do api.anthropic.com samą nazwę hosta. To drugie wyłącza tylko klucz skipWebFetchPreflight: true, a wtedy ogranicz WebFetch regułami uprawnień.
# Amazon Bedrock
export CLAUDE_CODE_USE_BEDROCK=1
export AWS_REGION=us-east-1
# Agent Platform w Google Cloud (dawniej Vertex AI)
export CLAUDE_CODE_USE_VERTEX=1
export CLOUD_ML_REGION=eu
export ANTHROPIC_VERTEX_PROJECT_ID=twoj-projekt Aktualizacja: od wersji 2.1.285 administrator może przypiąć dostawcę kluczem allowedProviders w ustawieniach zarządzanych, np. ["bedrock"]. Sesja na dostawcy spoza listy nie wystartuje, a przełączenie na niego w trakcie pracy zostanie odrzucone. Bez tego klucza deweloper może sam przejść na API Anthropic.
Jeśli kod ma w ogóle nie opuszczać maszyny, zostają modele lokalne. Ollama wystawia API zgodne z Anthropic, więc Claude Code podłączysz komendą ollama launch claude albo zmienną ANTHROPIC_BASE_URL=http://localhost:11434. Pilnuj dwóch rzeczy: modele z dopiskiem :cloud działają na serwerach Ollamy, nie lokalnie, a przy większym repozytorium ustaw okno kontekstu na co najmniej 64k.
Checklista: nowy projekt z Claude Code
.claude/settings.jsonz deny rules, łącznie z komendami DNS z sekcji 02 (CVE-2025-55284).- Sandbox włączony, z obiema flagami wymuszenia z sekcji 03; na natywnym Windows: deny rules + hooki.
- Hook
detect-secretszainstalowany i wykonywalny. .envw.gitignore, a w repo tylko.env.examplez placeholderami.- Sprawdź historię:
git log --all --full-history -- .env - Nigdy nie uruchamiaj agenta jako root, sudo ani Administrator.
cleanupPeriodDays: 7w settings.json.
Test, czy blokady działają
# Zapytaj agenta: "pokaz zawartosc pliku .env"
# Oczekiwane: odmowa z powodu uprawnien
# Zapytaj: "zapisz do app.py: password = 'test123abc'"
# Oczekiwane: operacja zablokowana przez hook Chcecie, żeby cały zespół pracował z AI bezpiecznie?
Skonfigurujemy warstwy ochrony na Waszym repozytorium i wdrożymy je w zespole. Audyt 90 minut wystarczy, żeby sprawdzić, czy ma to u Was sens.