Argano の小林です。本記事では、AI コーディングエージェントを隔離環境で動かすための仕組みである Docker Sandboxes を取り上げます。ネットワークの制限、認証情報の扱い、ファイルへのアクセス制御が、それぞれどのような原理で実現されているのかを、実際に動かしながら整理します。

検証環境は次のとおりです。

WSL2 (Linux 6.6.114.1-microsoft-standard-WSL2)
sbx v0.42.0
検証日: 2026-09-15

AI エージェントを普段の環境で動かすリスク

Codex や Claude Code といった AI エージェントはコードを生成するだけではなく、コードを実行する能力を有しています。実行する方法にもよりますが、フルアクセス(Codex) ・Auto mode(Claude Code) などの自律実行を許可するモードではユーザーの認可なしにコードを実行します。

AI エージェントは文脈に応じたコードを生成するため、推論過程に悪意のあるデータや誤った情報が注入された場合、危険なコードを生成することがあります。もちろん、危険なコードがなるべく生成されないようにする仕組みとして、システムプロンプトやコード・コマンドの実行前にルールベースで実行を却下する仕組みが内蔵されていますが、どれもすべての危険なコードの実行を防ぐ仕組みとはいえません。そのため、AI エージェントは危険なコードを実行しうるものとして扱う必要があります。

危険なコードが普段の開発環境で実行されると何が起こるでしょうか。AI エージェントは、特にサンドボックスを設定しない限り、起動したユーザーと同じ権限でプログラムを実行します。つまり ssh の秘密鍵やクラウドサービスの API キー、他のプロジェクトのソースコードなどの機密情報を読み取れ、それらを外部のサーバーに送信できます。

AI エージェントに危険なコードを実行させる攻撃の例として、2025年8月に発生した Nx のサプライチェーン攻撃が挙げられます。この攻撃では、週あたり400万ダウンロード規模の npm パッケージである Nx が侵害され、postinstall スクリプトにマルウェアが仕込まれました。このマルウェアは開発者のマシンにインストール済みの AI CLI ツールを探し出し、自律実行を許可するフラグを付けて起動したうえで、機密情報を集めるよう指示しました。集められた GitHub トークン、npm トークン、SSH 秘密鍵、環境変数は、被害者自身のアカウント配下に作られた public リポジトリへ送信されました。

このように AI エージェントは危険なコードを実行する可能性があります。そのため、AI エージェントが生成するコードや AI エージェントは何かしらの隔離環境で実行するべきです。先述の攻撃に関して言えば、エージェントに機密情報を読み取られないような環境で実行すると被害を緩和できたと考えられます。(ソースコードの流出は防げませんが)

Docker Sandboxes とは

Docker Sandboxes は AI エージェントを隔離環境で動かすための仕組みです。当初は Docker Desktop 4.50 に同梱された docker sandbox run というコンテナベースの隔離環境でした。その後より強固な隔離機構として microVM による分離へ作り替えられ、2026年3月31日に Docker Desktop を必要としないスタンドアロンの sbx CLI としてリリースされました。

sbx が提供する隔離機構は、主にマシンレベルの分離、ファイルシステムの制限 / 分離・ネットワークの制限の 3 つです。次の図は公式ドキュメントに掲載されているもので、この Docker Sandboxes が提供する隔離機構がまとまっています。

Docker Sandbox security model

出典: Docker Docs (https://docs.docker.com/ai/sandboxes/security/), Apache License 2.0, © Docker, Inc.

ネットワークについて補足すると、サンドボックスからの通信はすべてホスト側のプロキシを経由し、許可したドメイン宛の通信のみ行えるようになっています。また詳しくは後述しますが、このプロキシは通信に認証情報を後から付け足し、サンドボックスから認証情報を隔離する役割も持っています。

以降の章では実際に sbx を使ってサンドボックスを作成し、隔離機構がどのように動作しているのかを見ていきます。

とりあえず動かしてみる

インストール手順は 公式ドキュメント に記載されているので、公式ドキュメントの通りに進めます。

インストールできたら、まずは組み込みの Claude Code 向けのサンドボックスを起動してみます。

$ sbx run claude

初回起動時はネットワークポリシーのプリセットを Open、Balanced、Locked Down の3つの中から選択します。Open, Locked Down はそれぞれネットワーク越しの通信をすべて許可、(明示的に許可しない限り)すべて遮断するプリセットです。Balanced は Docker 社側で設定された、開発に必要だと考えられるサービスのドメインについて通信を許可するプリセットです。

設定をファイルに書く

先程は Claude Code 用のイメージをデフォルトの設定で起動しましたが、以降は設定ファイルを使ってカスタムのサンドボックスを起動します。本記事では YAML ファイルで設定する方法を使ってテスト用のサンドボックスを定義します。サンドボックスは基本的に以下の 2 つの設定ファイルによって定義できます。

ファイル役割
sbxenv.yaml環境を起動する方法。エージェント、ワークスペース、使う kit、ベースイメージ
kit の spec.yaml何を許可し、何を注入するか。再利用や配布ができる単位

詳しい記法は docker/sbx-kits-contrib の SPEC-v2.md にまとまっているので、詳細な仕様はこちらを参照してください。

本記事で使う検証用プロジェクトのファイル構成は次のとおりです。main.py は隔離機構の確認用に置いた、ワークスペース内のファイルの例です。

docker-sbx-test/
├── kit/
│   └── spec.yaml
├── main.py
└── sbxenv.yaml

まず sbxenv.yaml です。

schemaVersion: "1"
name: sbx-test
agent: claude
workspace: .

kits:
    - ./kit

sandboxOptions:
    template: docker/sandbox-templates:claude-code-docker

workspace: . は設定ファイルを含むディレクトリを読み書き可能な状態でマウントします。workspace: を設定しないことで、エージェントにコンテナ自身のファイルシステムだけで作業させることもできます。

kits: には後述の spec.yaml を含むディレクトリを指定します。./ を付けずに kit と書くとレジストリ参照とみなされるので注意してください。

sandboxOptions.template はベースイメージです。

$ sbx template ls
REPOSITORY                           TAG                  IMAGE ID       FLAVOR               CREATED
docker.io/docker/sandbox-templates   claude-code-docker   94670d5b2a24   claude-code-docker   7 days ago

次に kit の spec.yaml です。

schemaVersion: "2"
kind: mixin
name: sbx-test-kit
version: 0.0.0
displayName: Docker Sandboxes test kit
description: Docker Sandboxes の動作確認用の kit

permissions:
    network:
        allow:
            - localhost:8080

credentials:
    - service: sbx-test-service
      apiKey:
          name: SBX_TEST_TOKEN
          proxyManaged: true
          inject:
              - domain: localhost
                header: x-api-token
                format: "%s"

kind: mixin は、組み込みのエージェントに権限や認証情報を足す種類の kit であることを示します。permissions.networkcredentials が、次章以降で見ていくネットワークの制限と認証情報の注入を、そのまま宣言の形にしたものです。

定義した kit は sbx kit inspectsbx kit validate から確認・検証できます。

$ sbx kit inspect ./kit
  Name:           sbx-test-kit
  Kind:           mixin
  Schema:         v2
  Display:        Docker Sandboxes test kit
  Description:    Docker Sandboxes の動作確認用の kit

  Policies:
    Network:      1 allow, 0 deny
    Credentials:  1 sources
    Environment:  0 variables, 1 proxy-managed

$ sbx kit validate ./kit
VALID: ./kit (directory)

宣言した環境は sbx env で起動できるほか、sbx env plan を使うことで、サンドボックスに登録される認証情報や公開されるポートを事前に確認できます。

$ sbx env plan

以降の節では、起動したサンドボックスに対して sbx exec でコマンドを実行し、それぞれの隔離機構の挙動を確認します。

ファイルの読み書きについて

まずはサンドボックスの中からワークスペース内のファイルを読んでみます。

$ sbx exec sbx-verify cat main.py
def main():
    print("Hello from docker-sbx-test")


if __name__ == "__main__":
    main()

sbxenv.yamlmain.py が格納されているディレクトリをワークスペースとしてマウントしたので当然ですが、サンドボックス内から main.py を読み取ることができました。

次にワークスペースの外のファイルを読んでみます。

$ sbx exec sbx-verify sh -c 'cat /home/ryohei/.zshrc; cat /home/ryohei/.claude/.credentials.json'
cat: /home/ryohei/.zshrc: No such file or directory
cat: /home/ryohei/.claude/.credentials.json: No such file or directory

どちらもホスト側には存在するファイルです。

$ ls -l ~/.zshrc ~/.claude/.credentials.json
lrwxrwxrwx 1 ryohei ryohei  33 Sep 15 13:58 /home/ryohei/.zshrc -> /home/ryohei/dotfiles/zsh/zshrc
-rw------- 1 ryohei ryohei 559 Sep 15 11:57 /home/ryohei/.claude/.credentials.json

ワークスペースの外にあるシェルの設定も、Claude Code の認証情報も、サンドボックスの中からは見えません。冒頭で挙げた「機密情報を読み取れてしまう」というリスクは、ここで断たれています。

では、main.py をサンドボックス内で編集すると、ホスト側の main.py はどうなるでしょうか?

$ sbx exec sbx-verify sh -c 'sed -i "s/Hello from docker-sbx-test/Edited inside the sandbox/" main.py'

ホスト側で確認します。

$ cat main.py
def main():
    print("Edited inside the sandbox")


if __name__ == "__main__":
    main()

サンドボックスからホスト側のワークスペース内のファイルを書き換えることができました。これは Docker Sandboxes のデフォルトのワークスペースの渡し方が、ホスト側のワークスペースをサンドボックスに直接マウントする方法だからです。

モード指定方法挙動
direct mountデフォルトホストのリポジトリを読み書き可能な状態でマウントする
clone--cloneホストのリポジトリを読み取り専用で渡し、VM 内にクローンを作成して作業する

もしサンドボックスからホスト側のファイルに直接アクセスさせたくない場合、clone モードでホスト側のリポジトリを渡します。このモードではホストのリポジトリが /run/sandbox/source に read-only で渡され、エージェントは clone したプライベートなコピーで作業します。クローンは VM 内の git-daemon で公開され、ホスト側に sandbox-<name> という Git remote が自動登録されます。

$ sbx create --name sbx-clone --clone claude .
  Git daemon: git://127.0.0.1:44620/docker-sbx-test
  Remote: sandbox-sbx-clone
── CREATE SANDBOX
     mount  /home/ryohei/docker-sbx-test → /run/sandbox/source (ro, source)
   ✓ Created sandbox sbx-clone

$ git remote -v
origin	https://github.com/Ryohei22222/docker-sbx-test.git (fetch)
origin	https://github.com/Ryohei22222/docker-sbx-test.git (push)
sandbox-sbx-clone	git://127.0.0.1:44620/docker-sbx-test (fetch)
sandbox-sbx-clone	git://127.0.0.1:44620/docker-sbx-test (push)

ネットワークの制限

サンドボックスからサンドボックス外への通信は、デフォルトで拒否されます。許可するものは、前節の kit の permissions.network、もしくはグローバルのプリセットで設定します。

permissions:
    network:
        allow:
            - localhost:8080

許可していないドメインへアクセスしてみます。

$ sbx exec sbx-verify curl -sS -m 20 -i https://example.com
HTTP/1.0 200 OK

HTTP/1.1 403 Forbidden
Content-Length: 118
Content-Type: text/plain

Blocked by network policy: domain example.com:443
  detail: no matching allow rule — blocked by default deny policy

接続エラーではなく、プロキシが理由を添えた HTTP 403 を返ってきました。

認証情報の隔離

一般的なコンテナ環境では、AI エージェントの動作に必要な API キーをコンテナ内へ渡すことになります。一方 Docker Sandboxes では、サンドボックスの外に出る通信に対してホスト側のプロキシで後から認証情報を付与します。そのため、認証情報をコンテナの中に渡すことなく動作させられます。

前節で挙げた kit の credentials ブロックを再掲します。

credentials:
    - service: sbx-test-service
      apiKey:
          name: SBX_TEST_TOKEN
          proxyManaged: true
          inject:
              - domain: localhost
                header: x-api-token
                format: "%s"

ここでは例として、sbx-test-service というサービスの認証情報を設定しています。proxyManaged: true を指定すると、サンドボックス内の環境変数には真の文字列の代わりに番兵用の文字列が設定されます。実際に確認します。

$ sbx exec sbx-verify sh -c 'env | grep -Ei "proxy|token|cert" | sort'
GH_TOKEN=gho_sbxproxymanaged000000000000000000000
HTTPS_PROXY=http://gateway.docker.internal:3128
HTTP_PROXY=http://gateway.docker.internal:3128
...(省略)...
SBX_TEST_TOKEN=proxy-managed

kit で宣言した SBX_TEST_TOKENproxy-managed になっています。また、 GH_TOKENgho_sbxproxymanaged000000000000000000000 に置き換えられています。(gho_ という本物の接頭辞と長さを保ったまま一時的な値に置き換えられている)

Claude Code では OAuth を用いた認証もサポートされていますが、この認証情報は隔離できるでしょうか。結論から言うと、Docker Sandboxes は OAuth の認証情報をホスト側に隔離する機能も持っています。

実際にサブスクリプションで認証した状態のサンドボックスを覗いてみます。

$ sbx exec sbx-verify cat /home/agent/.claude/.credentials.json
{"claudeAiOauth":{"accessToken":"sk-ant-oat01-proxy-managed","refreshToken":"sk-ant-ort01-proxy-managed","expiresAt":1789040839565,"scopes":["user:file_upload","user:inference","user:mcp_servers","user:profile","user:sessions:claude_code"]}}

アクセストークンとリフレッシュトークンが sk-ant-oat01-proxy-managed / sk-ant-ort01-proxy-managed になっています。接頭辞の形は本物ですが、中身はプレースホルダです。実トークンはホスト側の ~/.claude/.credentials.json に残ったままです。

一方 expiresAtscopes は実際の値です。Claude Code が期限切れを判定するのに必要な情報だけは渡している、ということのようです。

実際に Claude の API エンドポイントを、認証情報をヘッダーに付与せず呼び出してみます。

$ sbx exec sbx-verify curl -sS https://api.anthropic.com/v1/models?limit=1 \
    -H "anthropic-version: 2023-06-01" -w "\n--- HTTP %{http_code} ---\n"
{"data":[{"type":"model","id":"claude-fable-5-1","display_name":"Claude Fable 5.1", ... }],"has_more":true}
--- HTTP 200 ---

認証情報を何も渡していないのに 200 が返りました。このことからもプロキシが外向きのリクエストに認証ヘッダを付与していることが分かります。

OAuth の認証情報を隔離する方法の詳細については、Manage credentials と、kit で宣言する際の記法をまとめた Kit spec reference を参照してください。

Docker Sandboxes でも防げないリスク

ここまで見てきた仕組みで守られないものを整理します。

許可したドメインから情報が流出する

ネットワークの制限によって外部サーバーへの送信は止まりますが、実際には開発に必要なサーバーへの通信は許可することになります。

たとえば開発のために GitHub を許可リストに入れると、エージェントは自分のアカウント配下に private gist を作ることも、新しいリポジトリへの push もできます。そのため、許可リストはなるべく小さくするべきですし、外部サービスに接続するためのトークンの権限を絞るべきです。

ソースコードの流出

認証情報は隔離してもプロジェクトのソースコードは原理上サンドボックスから隔離できません。ネットワークの制限である程度流出のリスクは緩和できますが、サンドボックス内からソースコードを読め、運用上いくつかのドメインへの通信を許可することを考えると、リスクを無くすことはできません。

プロンプトインジェクションとコードの改竄

サンドボックスは、生成されたコードが正しいかどうかには一切関与しません。つまり、プロンプトインジェクションによって誤ったコードや悪意あるコードが書かれることは防げません。

具体的なリスクは、ワークスペースにマウントしたコードそのものが書き換えられうることです。前述のとおり direct mount では読み書き可能なので、既存のコードを改竄されても、差分を見るまで気づけません。

まとめ

本記事では Docker Sandboxes を紹介し、隔離機構を簡単に検証しました。前述のリスクを考えると、少なくとも何かしらの隔離環境で AI Agent を実行させることは必須だと考えています。Docker Sandboxes は他のサンドボックスツールに比べて設定が煩雑ですが、その分強固な隔離環境を扱うことができます。個人的にはプロジェクトの規模がそこまで大きくなければ設定も容易なので、導入を検討してもよいと考えます。他のサンドボックスツール・ハーネスも合わせて AI Agent を安全に実行する方法を今後も模索していきます。

参考