本文へスキップ
メニュー
自分に必要?エージェントが手元のマシンで触れられるもの仕組みエージェントとシステムの間にある層比較組み込みサンドボックス、Docker、VM設定タスクに必要なものだけを開けるセキュリティ脅威モデルとその限界ダウンロードバイナリ、チェックサム、リリースノートインストール
仕組み

ai-jail claudeと打つと何が起きるか

ai-jailはあなたのシステムの小さく閉じたコピーを作り、そこにプロジェクトを置いて、中でエージェントを起動します。壁はOS自体の機能なので、エージェントはフルスピードで動き、壁を切ることはできません。起動ごとに、ネットワークはエージェント自身のAPIホスト以外閉じるか、指定した少数のホストに開くか、全開かを選びます。

何が強制されるのかを知りたいエンジニアへ。それ以外の人には、最初の段落と最初の図で十分です。

起動時に起きること

毎回、一瞬で終わります。その後バックグラウンドに残るものはありません。

↔ 横にスワイプすると図全体を見られます

ai-jailは起動のたびにサンドボックスを新しく作り、終了時に捨てます。変更が残るのはプロジェクトだけです。

ルールを読む

ai-jailは、あなた自身の~/.ai-jailファイルを信頼します。プロジェクト内の.ai-jailファイルは信頼できないものとして扱い、サンドボックスを厳しくはできても、緩めることはできません。コマンドラインのフラグはどちらよりも優先されます。

サンドボックスを組み立てる

ai-jailは、エージェントが存在する前に、下で説明する各層を用意し、手元のツールチェーン(mise、cargo、npmなどのキャッシュ)を読み取り専用か、ジェイル専用のキャッシュとしてマップします。設定ファイルが読めなかったり不正だったりした場合は、弱いルールで起動せずに停止します。

中でエージェントを起動する

エージェントも、それが起動するスクリプトやパッケージ、MCPサーバーも、同じ壁を引き継ぎます。エージェントが終了すると、ai-jailも終了します。

すべてのフラグと設定キー

ネットワークへの3つの道

起動のたびに3つのネットワークモードから1つを選びます。デフォルトは最も厳しく、フィルタ付きプロキシが通すもの以外に外への経路はありません。通すのは、両プラットフォームで既知のエージェント自身のAPIホストと、ツールチェーンが有効なLinux(デフォルト)での短いパッケージレジストリ一覧です。残りの2つは意図して渡すフラグです。

↔ 横にスワイプすると図全体を見られます

デフォルトは無効で、エージェント自身のAPIホストと、Linuxではレジストリへの門が1つだけ開いています。フィルタ付きは、指定したホストだけへの門を開けます。全開は、ネットワーク側の壁を取り去ります。

無効

デフォルト。サンドボックスは外への経路のない専用のネットワーク名前空間を得ますが、フィルタ付きプロキシ経由だけは例外です。既知のエージェントなら、自身のAPIホストをLinuxでもmacOSでもプロキシが通すので、素のai-jail claudeが動きます。Linuxでツールチェーンが有効なら(デフォルト)、固定のパッケージレジストリ一覧も通すので、npm installやcargo buildが動きます。macOSではレジストリは閉じたままです。--no-networkで完全にオフラインになります。

フィルタ付き

--allow-host HOST。繰り返し指定できます。名前空間は閉じたままで、中の小さなブリッジが通信を外のCONNECTプロキシへ転送し、プロキシは指定したホストとそのサブドメインにだけ接続します。プロキシは名前を外側で一度だけ解決し、確認済みのアドレスに接続します。ai-jailは中でhttp_proxyを設定し、それを無視するプログラムはどこにも届きません。

全開

--network。ネットワーク側の壁はなくなり、エージェントは読めるものを何でも外へ送れます。

LinuxmacOS
フィルタ付きモードの柵ネットワーク名前空間そのものと、その中のブリッジプロキシのポートへの外向き接続だけを許可するsandbox-execのルール1つ
サンドボックス内のDNS失敗します。名前はプロキシが外側で解決します。システムのリゾルバに柵がかからないので、低帯域のDNSチャネルが残ります
フラグ、注意点、プロキシが記録するもの

外側から内側へ、層を順に見る

ai-jailは、1枚の壁だけで持ちこたえられるとは考えていません。Linuxでは、エージェントはカーネルが強制する5枚の壁の内側にいます。さらに、入るものと出るものに1つずつフィルターがかかります。

↔ 横にスワイプすると図全体を見られます

どの壁も、1つ外側の壁のミスを補います。
  1. 名前空間

    bubblewrap
    これは何か
    名前空間は、カーネルがプロセスに与える、そのプロセス専用のシステムの見え方です。ai-jailはその作成をbubblewrapに任せます。Flatpakがデスクトップアプリのサンドボックス化に使っているのと同じ小さなツールで、rootは要りません。
    何を止めるか
    エージェントには専用のプロセス一覧と専用のホスト名(ai-sandbox)が与えられます。ホスト上のプログラムとのプロセス間通信の経路はなく、ネットワーク名前空間には、--allow-hostか--networkで開けない限り外への経路がありません。ai-jailが落ちれば、中のものもすべて一緒に落ちます。
  2. ファイルシステム

    マウント
    これは何か
    名前空間の中には、ai-jailがマウントしたものしか存在しません。プロジェクトは実際のパスのまま読み書き可能、/usrなどのシステムディレクトリは読み取り専用です。ホームディレクトリと/tmpは新しく作られ、メモリ上に置かれます。手元のツールチェーン(mise、cargo、npmのキャッシュ)は、この新しいホームの中に読み取り専用か、ジェイル専用のキャッシュとしてマップされます。
    何を止めるか
    ~/.ssh、~/.aws、~/.gnupg、~/.docker、ブラウザのプロファイルは組み込みのリストに載っており、決してマウントされません。例外はハーネス自身の状態ディレクトリ、たとえばClaudeの~/.claudeです。ai-jailはこれをデフォルトで読み書き可能でマウントするので、エージェントはログイン済みで起動します。--no-agent-stateなら外に置かれます。プロジェクトの外に書いたものは、セッションが終わると消えます。
  3. Landlock

    kernel 5.13+
    これは何か
    LandlockはLinuxカーネルの機能で、プロセスがファイルへのアクセス権を自分から恒久的に手放せるようにします。ai-jailはこれを使い、ファイルシステムのルールをカーネル内の2つ目の許可リストとしてもう一度適用します。
    何を止めるか
    マウントの層にミスや抜け道があっても、それだけではリスト外のパスに届きません。読み取り専用は読み取り専用のままです。カーネル6.12以降では、抽象Unixソケットとシグナルも可能な範囲で制限します。Landlockに対応していない古いカーネルでは、ai-jailはその旨を表示し、残りの層で続行します。
  4. seccomp

    システムコール
    これは何か
    プログラムはシステムコールを通じてカーネルに処理を依頼します。seccompはその呼び出しにかけるフィルターです。ai-jailはこれを使い、コーディングエージェントにはまず必要のないシステムコールを拒否します。
    何を止めるか
    フィルターが止めるのは、ptrace、mount、bpf、カーネルモジュール、io_uring、カーネルキーリング、rawソケット、そしてターミナルにキー入力を打ち込める呼び出しであるTIOCSTIです。コンパイラやランタイムが動き続けるよう、あえてブロックリスト方式にしています。Landlockとseccompの適用前に起動される唯一のプロセスは、フィルタ付きの通信を外へ運ぶ小さなブリッジで、これだけは制限を受けません。
  5. リソース制限

    rlimits
    これは何か
    プロセスツリーが使える量にカーネルがかける上限です。プロセスは4,096個、開けるファイルは65,536個までで、コアダンプは無効です。ロックダウンモードでは1,024と4,096に下がります。
    何を止めるか
    fork爆弾や暴走したスクリプトは、マシンを固まらせる前に、ジェイル内の上限に当たって止まります。エージェントが上限を引き上げ直すことはできません。
  6. 環境変数の許可リスト

    入るもの
    これは何か
    シェルには変数がたくさんあり、その中にはAPIキーも混ざっています。ai-jailは環境を空にして、短いリストだけを渡します。PATH、HOME、TERM、ロケール、プロキシと証明書の設定です。
    何を止めるか
    シェルにexportしてあるトークンやクラウドの認証情報は、エージェントに届きません。例外は起動したハーネス自身のAPIキー、たとえばClaudeのANTHROPIC_API_KEYで、ログイン情報と一緒にデフォルトでコピーされます。--no-agent-stateで止められます。タスクに必要なときは、--envで名前を指定してほかの変数を1つずつ渡します。
  7. ターミナルプロキシ

    出るもの
    これは何か
    エージェントは専用の擬似ターミナルの向こうで動き、その出力は画面に届く前にターミナルのパーサーを通ります。最下行にai-jailのステータスバーを描くのもこのプロキシです。
    何を止めるか
    プロキシは、クリップボードに触れたりターミナルに問い合わせたりするエスケープシーケンスを取り除きます。tmuxやzellijの中では、入れ子のターミナル同士がリサイズで衝突するため、プロキシは自動で無効になります。

macOSでは壁が薄くなる

macOSには名前空間もLandlockもseccompもありません。ai-jailは同じポリシーを、Apple純正のサンドボックスであるsandbox-execのプロファイルに変換します。これがLinuxの隔離と同等ではないことは、ai-jailのドキュメントにもはっきり書いてあります。

↔ 横にスワイプすると図全体を見られます

macOSでも同じポリシーとフラグが使えますが、壁の数は少なくなります。
LinuxmacOS
バックエンドbubblewrap、続いてLandlock、seccomp、リソース制限起動のたびに生成したプロファイルを使うsandbox-exec。Appleはこれを非推奨にしていますが、カーネル拡張なしで使えるもっと良い手段はありません。
ホームディレクトリメモリ上の新しいホーム。本物のホームはマウントされません。プロファイルは全体の読み取りを禁止した状態から始め、エージェントに必要なパスだけを許可します。本物のホームは閉じたままです。
/tmp専用で、終了時に破棄マウント名前空間がないため、ホストの/tmpです。TMPDIRは起動ごとに作る専用フォルダを指し、許可される一時パスはそこだけです。
コピーオンライトのマップ--overlay-mapを使うと、エージェントはコピーに書き込みます読み取り専用のマップとして扱われます
ネットワークデフォルトは閉じています:既知のエージェント自身のAPIホストと、ツールチェーンが有効なときに許可されるパッケージレジストリ以外に、外への経路はありません。--allow-hostか--networkで広げ、--forward-portでホストのループバックのポート1つを中継し、--no-networkですべて閉じます。--lockdownでは、--networkを付けても開いたネットワークは常にブロックされます。同じデフォルトと同じフラグで、既知のエージェントのAPIホストも含みますが、--forward-port、レジストリ、ツールチェーンのキャッシュのマップはLinux限定なのでありません。ロックダウンはここでも開いたネットワークをブロックします。
ほかのプログラム見えません。プロセス一覧は専用で、ホストのIPCもありません--macos-host-ipcを渡さない限り、Mach、IOKit、ホストのIPCは拒否されます

なぜこの部品を選んだか

ai-jailは、自前で書くセキュリティ関連のコードをできるだけ少なくしています。土台はbubblewrapです。小さく、主要なディストリビューションすべてでパッケージになっていて、Flatpakを通じて毎日使われています。その上にカーネルの機能を重ねます。

選択肢採用しなかった理由
Firejail用は足せますが、setuid rootのバイナリであり、その設計に起因するCVEがいくつも出ています。bubblewrapはrootなしで動きます。
bubblewrapをRustで書き直す上流で修正が入り続ける約50 KBの依存を1つ避けるために、セキュリティ上重要な500行超のコードを自分たちだけで保守し、パッチを当て続けることになります。
nsjail機能は十分ですが、サーバー向けの作りで、設定はprotobuf形式のファイルです。パッケージとして入手できる環境も限られます。
systemd-nspawnsystemdが必須なので、コンテナの中やsystemdのないシステムでは動きません。

検討の全文を読む

読み切れる小ささ

ツール全体が1本の同期的なRustプログラムです。asyncランタイムもデーモンもコンテナイメージもありません。

1
インストールするバイナリ
11
直接の依存
959
ソース内のユニットテスト
23
実際のサンドボックスからの脱出を試みるテスト

依存はai-jailリポジトリのバージョン2.9.0で、テストはバージョン2.9.0で数えた値です。

エージェントを檻の中に

ai-jailは単一のバイナリで、デーモンもroot権限も要りません。いつものコマンドの前に1語足すだけです。

terminal
brew tap akitaonrails/tap && brew install ai-jailai-jail claude