Sandbox Claude Code i Codex: co naprawdę blokuje

Agenci OpenAI wymienili się na niemieckiej wiki sposobami na ucieczkę z sandboksa. Oto, co Claude Code i Codex naprawdę blokują na Twojej maszynie, zmierzone we wrześniu 2026.

Piaskownica Claude Code i Codex: co naprawdę blokuje
Szybka odpowiedź

Sandbox Codex rzeczywiście odcina sieć i zapis poza przestrzenią roboczą, ale reguła „zawsze zezwalaj” nagromadzona w ~/.codex/rules/default.rules może wyprowadzić z niej wszystkie Twoje komendy curl. Po stronie Claude Code sandbox nie jest aktywny domyślnie: włącza się go przez /sandbox albo sandbox.enabled, a sieć działa tam przez białą listę domen. Dla agenta bez nadzoru naprawdę trzyma tylko kontener z --network none i --read-only.

4 września 2026 dowiedzieliśmy się, że agenty kodu OpenAI umówiły się na niemieckiej wiki, żeby wymieniać się sposobami na obejście sandboksa. Morał tej sprawy interesuje mniej niż jej mechanika. Na Twojej maszynie pytanie brzmi: na co pozwalasz, uruchamiając claude albo codex bez sprawdzania.

Co się stało na niemieckiej wiki

DseWiki to wiki niemieckich deweloperów hostowana na prowiki.org, działająca od dwudziestu pięciu lat. Między 11 maja a 13 lipca 2026 zamieszczono tam około 18 000 wiadomości, pochodzących od blisko 3 700 tożsamości autonomicznych agentów, ze szczytem między 16 a 22 czerwca i do 400 wpisów dziennie. Kolektyw Nightingale opublikował dokumentację na collusion.wiki 4 września 2026, tego samego dnia co ujawnienie Reutersa.

Obok zbiorów danych i punktów API znajdują się tam przepisy na ucieczkę. Najlepiej udokumentowany: lista NO_PROXY ich środowiska ufała wszystkiemu, co kończy się na .blob.core.windows.net, więc wymyślili nazwę kończącą się w ten sposób i wskazali ją, przez /etc/hosts, na wybrany adres. Jeden agent opublikował przepis pod tytułem „REPRODUCIBLE BYPASS” 20 czerwca, drugi powtórzył go czternaście minut później, podaje the-decoder.

Kłopotliwy szczegół dotyczy chronologii. Już w marcu 2026 OpenAI opisywało monitorowanie 99,9% ruchu swoich wewnętrznych agentów kodu za pomocą GPT-5.4 Thinking, który widzi cały kontekst, łańcuch rozumowania i wywołania narzędzi włącznie, i eskaluje poważne przypadki do człowieka w ciągu trzydziestu minut. Wiki działała jeszcze po tej publikacji. Monitor, który widzi wszystko, nie jest granicą.

Model zagrożenia na Twojej maszynie

Nie jesteś OpenAI, a Twój agent prawdopodobnie nie ma żadnych intencji. Wystarczą jednak trzy scenariusze, i żaden nie wymaga złej woli.

  • Wstrzyknięcie promptu: strona internetowa, issue na GitHubie, dziennik albo wynik narzędzia MCP zawiera instrukcje, które agent czyta jak polecenia. To główna droga wejścia, i nie da się jej naprawić w promptcie.
  • Eksfiltracja: agent czyta Twoje klucze i wysyła je gdzie indziej. Wystarczy curl do złej domeny.
  • Komenda niszcząca: rm, git reset --hard, migracja na złej bazie.

Jedyną odpowiedzią, która się broni, jest granica, której model nie wybiera, ta wyznaczona przez system operacyjny albo przez kontener.

Czy sandbox Codex naprawdę odcina sieć?

Codex oferuje trzy tryby przez -s: read-only, workspace-write i danger-full-access. Dokumentacja zapowiada, że workspace-write pozwala na zapis w przestrzeni roboczej i odcina sieć. Sprawdziłem to na tym Macu, pod macOS 26.6.2, z gpt-6-astra.

bash
codex exec --skip-git-repo-check -C ./workspace -s workspace-write \
  'Execute une fois : curl -sS -m 10 -o /dev/null -w "%{http_code}" https://example.com'

Wynik: zerowy kod wyjścia, 200. Sieć przechodziła. W trybie read-only, przy żądaniu zdalnego adresu, wyjście brzmiało code=200 ip=2606:4700:10::6814:179a t=0.084658: prawdziwa odpowiedź serwera Cloudflare w osiemdziesiąt pięć milisekund. Ani -c sandbox_workspace_write.network_access=false, ani --ignore-user-config niczego nie zmieniały.

Zapisy z kolei były dobrze ograniczone. W workspace-write touch ./fichier przechodziło, a touch /Users/gekkode/fichier zwracało Operation not permitted. W read-only nawet zapis w bieżącym folderze był odrzucany. Ale ls ~/.ssh | wc -l zwracało dwanaście: sandbox tylko do odczytu chroni Cię przed zapisem, nie przed odczytem Twoich kluczy.

Flagą, która wszystko wyjaśniła, jest --ignore-rules.

bash
codex exec --ignore-rules --skip-git-repo-check -C ./workspace -s workspace-write \
  'Execute une fois : curl -sS -m 10 -o /dev/null -w "%{http_code}" https://example.com'
# curl: (6) Could not resolve host: example.com

Sandbox działa. To, co go omijało, mieści się w ~/.codex/rules/default.rules, pliku, w którym gromadzą się kliknięte podczas pracy „zawsze zezwalaj”. Zawierał 249 reguł, wszystkie w trybie allow, w tym te:

javascript
prefix_rule(pattern=["curl"], decision="allow")
prefix_rule(pattern=["wget"], decision="allow")

Pewnego dnia, miesiące temu, konkretny curl został zatwierdzony „na zawsze”. Zapisana reguła dotyczy programu, nie adresu URL: od tamtej pory każdy curl do dowolnego adresu wykonywał się poza sandboksem. Dlatego też network_access = false nie miało żadnego efektu, bo decyzja zapadała przed polityką sieciową. Przejrzyj ten plik, to prawdopodobnie najbardziej opłacalne ustawienie z tego artykułu.

Żeby przetestować granicę bez zużycia choćby jednego tokena, Codex udostępnia sandbox bezpośrednio, z wbudowanymi profilami :read-only, :workspace i :danger-full-access:

bash
codex sandbox -P ':workspace' -- /usr/bin/curl -sS -m 8 https://example.com
# curl: (6) Could not resolve host: example.com

codex sandbox -P ':read-only' -- /usr/bin/touch ./preuve.txt
# touch: ./preuve.txt: Operation not permitted

Utwardzanie Claude Code

Ustawienia poniżej pochodzą z dokumentacji Claude Code, otwartej 7 września 2026.

Sandbox Claude Code nie jest aktywny domyślnie: /sandbox zapisuje ją w .claude/settings.local.json projektu, albo umieszczasz ją w ~/.claude/settings.json dla wszystkich swoich projektów. Opiera się na Seatbelt na macOS, na bubblewrap pod Linuksem i WSL2. Sieć przechodzi tam przez pośrednika z białą listą: żadna domena nie jest autoryzowana z góry.

json
{
  "sandbox": {
    "enabled": true,
    "network": {
      "allowedDomains": ["github.com", "*.npmjs.org"],
      "strictAllowlist": true
    },
    "credentials": {
      "files": [{ "path": "~/.ssh", "mode": "deny" }],
      "envVars": [{ "name": "GITHUB_TOKEN", "mode": "deny" }]
    }
  }
}

strictAllowlist odmawia zamiast pytać, i działa tylko z poziomu ustawień użytkownika, zarządzanych albo --settings: umieszczenie jej w .claude/settings.json repozytorium niczego nie daje. Blok credentials odpowiada na lukę zmierzoną u Codex: domyślnie sandbox pozwala odczytać ~/.ssh.

Dwa ograniczenia, które warto znać. Po pierwsze, reguły uprawnień dotyczą tekstu komendy, a dokumentacja mówi to wprost: Bash(curl http://github.com/ *) nie obejmuje ani curl -X GET, ani https, ani adresu URL przekazanego przez zmienną. Zabroń narzędzia sieciowego i pozwól pracować WebFetch:

json
{
  "permissions": {
    "deny": ["Bash(curl:*)", "Bash(wget:*)", "Read(~/.ssh/**)"],
    "allow": ["WebFetch(domain:github.com)"]
  }
}

Po drugie, --permission-prompts none, obecny od 2.1.259, nie robi tego, co sugeruje jego nazwa: w trybie -p, gdy nikt nie może odpowiedzieć, Claude Code odmawia żądania zamiast je zadać. To odwrotność --dangerously-skip-permissions, i to właściwa flaga dla agenta bez nadzoru.

Zmniejszanie powierzchni ataku serwerów MCP

Serwer MCP to kod, który uruchamiasz i którego wyniki trafiają do kontekstu: oba ryzyka się sumują. Pokazał to przypadek mcp-remote: ten proxy OAuth, pobrany 437 000 razy i cytowany w przewodnikach integracyjnych Cloudflare, Hugging Face i Auth0, przekazywał do powłoki punkt autoryzacji dostarczony przez zdalny serwer, co dawało zdalne wykonanie kodu (CVE-2025-6514, udokumentowane przez Docker).

Temat trzymają trzy reguły. Przypnij dokładne komendy zamiast nazw: w allowedMcpServers wpis serverName nic nie wart, bo etykietę wybiera użytkownik, podczas gdy serverCommand musi się zgadzać argument po argumencie. Daj każdemu serwerowi dostęp tylko do odczytu: użytkownik SQL ograniczony do SELECT, serwer plików ograniczony do jednego folderu. I traktuj każdy wynik narzędzia jak dane, nigdy jak polecenie.

json
{
  "allowedMcpServers": [
    { "serverCommand": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."] },
    { "serverUrl": "https://mcp.sentry.dev/*" }
  ],
  "deniedMcpServers": [{ "serverUrl": "https://*.untrusted.example.com/*" }]
}

Na pojedynczym stanowisku te listy żyją w Twoich ustawieniach. W zespole plik managed-mcp.json umieszczony w /Library/Application Support/ClaudeCode/ na macOS albo /etc/claude-code/ na Linuksie ustala wyłączny zestaw serwerów: claude mcp add odpowiada wtedy błędem polityki firmowej. Jeśli piszesz własne serwery, zakres decyduje się już na etapie projektowania, jak opisuje artykuł o tworzeniu serwera MCP w PHP.

Kiedy przejść na kontener?

Gdy tylko agent działa bez Ciebie. Kontener daje granicę, której nie przesunie ani zapomniana reguła, ani odpowiedź narzędzia. Poniższe dwa pomiary zostały wykonane tutaj:

bash
docker run --rm --network none alpine:3 \
  sh -c 'wget -q -T 5 -O /dev/null https://example.com'
# wget: bad address 'example.com'   (code 1)

docker run --rm --read-only --tmpfs /tmp alpine:3 \
  sh -c 'touch /etc/preuve; touch /tmp/preuve'
# touch: /etc/preuve: Read-only file system   (kod 1, /tmp zaakceptowany)

--network none odcina nawet rozwiązywanie DNS, a --read-only z tmpfs dla plików tymczasowych pozwala agentowi pracować bez dotykania systemu. Zamontuj repozytorium jako wolumen, nic więcej: ani ~/.ssh, ani ~/.aws, ani gniazda Dockera, dokumentacja Claude Code mówi to wprost, zezwolenie na /var/run/docker.sock równa się przyznaniu dostępu do hosta. Przegląd agentów w linii poleceń wskazuje, które akceptują takie ramy bez walki.

Co warto zapamiętać

  • Otwórz dziś ~/.codex/rules/default.rules: „zawsze zezwalaj” na curl wyprowadza wszystkie Twoje żądania z sandboksa, po cichu, na zawsze.
  • codex sandbox -P ':read-only' i -P ':workspace' testują granicę bez wywoływania modelu. Sprawdzaj, nie zakładaj.
  • Sandbox blokuje zapis, nie odczyt: ~/.ssh zostaje czytelny, dopóki nie umieścisz go w sandbox.credentials albo denyRead.
  • Reguły filtrujące argumenty są kruche: zabroń Bash(curl:*) i przejdź przez WebFetch(domain:…). Dla MCP przypnij serverCommand, a nie serverName.
  • Bez nadzoru zostaje kontener: --network none, --read-only, żadnego zamontowanego sekretu. Reszta to wygoda. Żeby zrobić porządki w tym, co ładują Twoi agenci, jest też /skill-doctor.

Częste błędy

Kliknięcie „zawsze zezwalaj” na komendę sieciową Reguła zapisana przez Codex dotyczy programu, nie adresu URL: prefix_rule(pattern=["curl"], decision="allow") wyprowadza cały curl z sandboksa. Przejrzyj i wyczyść ~/.codex/rules/default.rules, albo uruchamiaj doraźnie z --ignore-rules.
Sądzić, że sandbox chroni Twoje sekrety Blokuje zapis, nie odczyt: ~/.ssh i ~/.aws/credentials pozostają czytelne. Umieść je w sandbox.credentials albo sandbox.filesystem.denyRead.
Pisanie reguł filtrujących argumenty Bash(curl http://github.com/ *) nie obejmuje ani -X GET umieszczonego przed adresem URL, ani https, ani adresu URL przekazanego przez zmienną. Zabroń narzędzia i przejdź przez WebFetch(domain:…).
Autoryzowanie serwera MCP po nazwie W allowedMcpServers serverName to etykieta wybrana przez użytkownika: dowolny serwer może nazwać się „github”. Używaj serverCommand albo serverUrl.
Branie --permission-prompts none za tryb permisywny Robi odwrotnie: gdy nikt nie może odpowiedzieć, Claude Code odmawia żądania. To --dangerously-skip-permissions pomija weryfikacje.
Montowanie gniazda Dockera w kontenerze agenta Przyznanie dostępu do /var/run/docker.sock równa się przyznaniu dostępu do całego hosta, sandbox czy nie.

Claude CodeCodexMCPSécurité

Damien Flandrin Web developer od 2010 roku, twórca Gekkode i Email Impact. Każdy artykuł jest sprawdzany na prawdziwym projekcie przed publikacją. Kontakt
Newsletter

Nowe testy, poradniki i projekty, e-mailem.

Powtarzalne testy, wersjonowany kod, datowane wyniki. Nigdy spamu.