Akademia · Bezpieczeństwo AI
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ę.
Ostatnia aktualizacja:
01 / TL;DR · Co działa, co nie
| 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.
02 / Warstwa 1 · Deny rules
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 |
{
"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.
Na Windows narzędzie nadal nazywa się Bash, ale pod spodem uruchamia PowerShell — blokuj komendy właściwe dla platformy:
// Linux / macOS
"Read(~/.ssh/**)", "Read(~/.aws/**)", "Read(~/.kube/**)",
"Bash(curl *)", "Bash(wget *)", "Bash(nc *)"
// Windows (PowerShell pod Bash)
"Bash(curl *)", "Bash(Invoke-WebRequest *)",
"Bash(Invoke-RestMethod *)", "Bash(iwr *)", "Bash(nc *)" W ścieżkach Windows w JSON ukośniki wsteczne muszą być podwojone.
03 / Warstwa 1b · Sandbox mode
Sandbox to najsilniejsza praktyczna ochrona dla komend powłoki: izoluje narzędzie Bash na poziomie systemu operacyjnego, łą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 |
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"allowUnsandboxedCommands": false,
"failIfUnavailable": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
} Granice izolacji: sandbox dotyczy tylko narzędzia Bash — 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.
sandbox.credentialsNie 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 z różnych zakresów się sumują, a jedyny dozwolony tryb to deny — żaden zakres nie poluzuje blokady. 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" }]
}
}
} Zmienne środowiskowe możesz też strippować globalnie — CLAUDE_CODE_SUBPROCESS_ENV_SCRUB usuwa poświadczenia Anthropic i providerów chmurowych ze wszystkich subprocesów.
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.
04 / Warstwa 2 · PreToolUse hook
Hook to skrypt powłoki uruchamiany przed wybranymi narzędziami. Kod wyjścia decyduje, co się stanie:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command", "command": ".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 // Linux — dopisuje kazda komende do logu
"PostToolUse": [{
"matcher": "Bash",
"hooks": [{ "type": "command",
"command": "jq -r '.tool_input.command' >> ~/.claude/command-audit-log.txt" }]
}] 05 / Wdrożenie · Warstwy miękkie i checklista
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 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. .claude/settings.json z deny rules — łącznie z komendami DNS z sekcji 02 (CVE-2025-55284).detect-secrets zainstalowany i wykonywalny..env w .gitignore, a w repo tylko .env.example z placeholderami.git log --all --full-history -- .envcleanupPeriodDays: 7 w settings.json.# Zapytaj agenta: "pokaz zawartosc pliku .env"
# Oczekiwane: odmowa z powodu uprawnien
# Zapytaj: "zapisz do app.py: password = 'test123abc'"
# Oczekiwane: operacja zablokowana przez hook Wdrożenie u Was
Skonfigurujemy warstwy ochrony na Waszym repozytorium i wdrożymy je w zespole. Audyt 90 minut wystarczy, żeby sprawdzić, czy ma to u Was sens.