seatbelt-sandboxer について
macOS アプリを分析し、許可リスト方式で権限を最小限にした Seatbelt サンドボックスプロファイルを生成するセキュリティスキルです。要件の確認、プロファイル作成、隔離環境での反復テストを案内します。
主な機能
- 01アプリのリソース要件の分析
- 02デフォルト拒否の Seatbelt 設定
- 03ファイル読み書き権限の範囲指定
- 04ネットワークアクセスポリシーの設定
- 05反復テストとサンドボックス調整
活用シーン
- 01macOS アプリのファイルアクセス制限
- 02異なるサブコマンドごとのプロファイル分離
- 03ビルドツールのネットワーク遮断
- 04生成したプロファイルでのアプリテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trailofbits/ skills --skill seatbelt-sandboxerインストール後、Claude Code で/seatbelt-sandboxerを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlassets/trail-of-bits-mark.svg
詳細
macOS Seatbelt サンドボックスのプロファイリング
アプリケーション向けに、最小限の権限を付与する許可リスト方式の Seatbelt サンドボックス設定を生成します。
使用する場面
- ユーザーが macOS 上のアプリケーションを「サンドボックス化」、「隔離」、または「制限」するよう求めている場合
- 制限されたファイル/ネットワークアクセスが必要な macOS プロセスをサンドボックス化する場合
- サプライチェーン攻撃が懸念される場合に、多層防御の隔離を作成する場合
使用しない場面
- Linux コンテナー(代わりに seccomp-bpf、AppArmor、または名前空間を使用してください)
- Windows アプリケーション
- 正当な理由から広範なシステムアクセスを必要とするアプリケーション
- サンドボックス化のオーバーヘッドが正当化されない、手早く実行する単発のスクリプト
プロファイリングの方法
ステップ 1:アプリケーションの要件を特定する
次のリソースカテゴリについて、アプリケーションに何が必要かを判断します。
| カテゴリ | 操作 | 一般的な用途 |
|---|---|---|
| ファイル読み取り | file-read-data, file-read-metadata, file-read-xattr, file-test-existence, file-map-executable | ソースファイル、設定、ライブラリの読み取り |
| ファイル書き込み | file-write-data, file-write-create, file-write-unlink, file-write-mode, file-write-xattr, file-clone, file-link | 出力ファイル、キャッシュ、一時ファイル |
| ネットワーク | network-bind, network-inbound, network-outbound | サーバー、API 呼び出し、パッケージのダウンロード |
| プロセス | process-fork, process-exec, process-exec-interpreter, process-info*, process-codesigning* | 子プロセスの起動、スクリプト |
| Mach IPC | mach-lookup, mach-register, mach-bootstrap, mach-task-name | システムサービス、XPC、通知 |
| POSIX IPC | ipc-posix-shm*, ipc-posix-sem* | 共有メモリ、セマフォ |
| Sysctl | sysctl-read, sysctl-write | システム情報(CPU、メモリ)の読み取り |
| IOKit | iokit-open, iokit-get-properties, iokit-set-properties | ハードウェアアクセス、デバイスドライバー |
| シグナル | signal | プロセス間のシグナル処理 |
| 疑似 TTY | pseudo-tty | 端末エミュレーション |
| システム | system-fsctl, system-socket, system-audit, system-info | 低レベルのシステムコール |
| ユーザー設定 | user-preference-read, user-preference-write | ユーザーのデフォルト設定の読み書き |
| 通知 | darwin-notification-post, distributed-notification-post | システム通知 |
| AppleEvents | appleevent-send | アプリケーション間通信(AppleScript) |
| カメラ/マイク | device-camera, device-microphone | メディアのキャプチャ |
| 動的コード | dynamic-code-generation | JIT コンパイル |
| NVRAM | nvram-get, nvram-set, nvram-delete | ファームウェア変数 |
各カテゴリについて、必要かどうかと具体的な範囲(パス、サービスなど)を判断します。
Webpack のような JavaScript バンドラーの build コマンドと serve コマンドなど、実行する操作が大きく異なるサブコマンドが複数ある場合は、次の手順を実行します。
- サブコマンドを個別にプロファイリングします
- 各サブコマンド用に個別のサンドボックス設定を作成します
- 元のバイナリのドロップイン置換として機能し、渡されたサブコマンドに応じて適切な Seatbelt プロファイルを使い、サンドボックス化したアプリケーションを実行するヘルパースクリプトを作成します
ステップ 2:最小限のプロファイルから始める
すべてを拒否し、必要不可欠なプロセス操作のみを許可する設定から始め、適切な名前を付けた .sb 拡張子の Seatbelt プロファイルファイルに保存します。
(version 1)
(deny default)
;; Essential for any process
(allow process-exec*)
(allow process-fork)
(allow sysctl-read)
;; Metadata access (stat, readdir) - doesn't expose file contents
(allow file-read-metadata)
ステップ 3:ファイル読み取りアクセスを追加する(許可リスト)
許可リスト方式の読み取りには、file-read* ではなく file-read-data を使用します。
(allow file-read-data
;; System paths (required for most runtimes)
(subpath "/usr")
(subpath "/bin")
(subpath "/sbin")
(subpath "/System")
(subpath "/Library")
(subpath "/opt") ;; Homebrew
(subpath "/private/var")
(subpath "/private/etc")
(subpath "/private/tmp")
(subpath "/dev")
;; Root symlinks for path resolution
(literal "/")
(literal "/var")
(literal "/etc")
(literal "/tmp")
(literal "/private")
;; Application-specific config (customize as needed)
(regex (string-append "^" (regex-quote (param "HOME")) "/\\.myapp(/.*)?$"))
;; Working directory
(subpath (param "WORKING_DIR")))
なぜ file-read* ではなく file-read-data を使うのですか?
file-read*は、あらゆるパスからの読み取りを含む、すべてのファイル読み取り操作を許可しますfile-read-dataは、リストに記載したパスからのファイル内容の読み取りのみを許可しますfile-read-metadata(広く許可)と組み合わせると、次のようになります。- ✅ どこでも stat/readdir できます(パス解決に必要です)
- ❌ 許可リスト外のファイル内容は読み取れません
ステップ 4:ファイル書き込みアクセスを追加する(制限付き)
(allow file-write*
;; Working directory only
(subpath (param "WORKING_DIR"))
;; Temp directories
(subpath "/private/tmp")
(subpath "/tmp")
(subpath "/private/var/folders")
;; Device files for output
(literal "/dev/null")
(literal "/dev/tty"))
ステップ 5:ネットワークを設定する
ネットワークアクセスには 3 つのレベルがあります。
;; OPTION 1: Block all network (most restrictive - use for build tools)
(deny network*)
;; OPTION 2: Localhost only (use for dev servers, local services)
;; Bind to local ports
(allow network-bind (local tcp "*:*"))
;; Accept inbound connections
(allow network-inbound (local tcp "*:*"))
;; Outbound to localhost + DNS only
(allow network-outbound
(literal "/private/var/run/mDNSResponder") ;; DNS resolution
(remote ip "localhost:*")) ;; localhost only
;; OPTION 3: Allow all network (least restrictive - avoid if possible)
(allow network*)
ネットワークフィルターの構文:
(local tcp "*:*")- 任意のローカル TCP ポート(local tcp "*:8080")- 特定のローカルポート(remote ip "localhost:*")- localhost のみへのアウトバウンド接続(remote tcp)- 任意のホストへのアウトバウンド TCP 接続(literal "/private/var/run/mDNSResponder")- DNS 用の Unix ソケット
ステップ 6:反復的にテストする
Seatbelt プロファイルを生成または編集した後、サンドボックス内で対象アプリケーションの機能をテストします。動作しないものがあれば、Seatbelt プロファイルを修正します。この手順を反復し、最小限の権限を付与した Seatbelt ファイルを生成し、生成した Seatbelt プロファイルを使用してサンドボックス化した状態でもアプリケーションが正常に動作することを実証的に確認できるまで続けます。
プログラムが完全に機能するために外部入力を必要とする場合(バンドル対象のアプリケーションを必要とする Javascript バンドラーなど)、よく知られた、できれば公式のソースからサンプル入力を探します。たとえば、Rspack バンドラーの次のサンプルプロジェクトを参照してください:https://github.com/rstackjs/rstack-examples/tree/main/rspack/
# Test basic execution
sandbox-exec -f profile.sb -D WORKING_DIR=/path -D HOME=$HOME /bin/echo "test"
# Test the actual application
sandbox-exec -f profile.sb -D WORKING_DIR=/path -D HOME=$HOME \
/path/to/application --args
# Test security restrictions
sandbox-exec -f profile.sb -D WORKING_DIR=/tmp -D HOME=$HOME \
cat ~/.ssh/id_rsa
# Expected: Operation not permitted
よくある失敗パターン:
| 症状 | 原因 | 対処法 |
|---|---|---|
| 終了コード 134(SIGABRT) | サンドボックス違反 | ブロックされている操作を確認します |
| 終了コード 65 + 構文エラー | 無効なプロファイル構文 | Seatbelt の構文を確認します |
既存ファイルに対する ENOENT | file-read-metadata が不足しています | (allow file-read-metadata) を追加します |
| プロセスがハングする | IPC 権限が不足しています | 必要に応じて (allow mach-lookup) を追加します |
Seatbelt 構文リファレンス
パスフィルター
(subpath "/path") ;; /path and all descendants
(literal "/path/file") ;; Exact path only
(regex "^/path/.*\\.js$") ;; Regex match
パラメーター置換
(param "WORKING_DIR") ;; Direct use
(subpath (param "WORKING_DIR")) ;; In subpath
(string-append (param "HOME") "/.config") ;; Concatenation
(regex-quote (param "HOME")) ;; Escape for regex
操作
ファイル操作:
(allow file-read-data ...) ;; Read file contents
(allow file-read-metadata) ;; stat, lstat, readdir (no contents)
(allow file-read-xattr ...) ;; Read extended attributes
(allow file-test-existence ...) ;; Check if file exists
(allow file-map-executable ...) ;; mmap executable (dylibs)
(allow file-write-data ...) ;; Write to existing files
(allow file-write-create ...) ;; Create new files
(allow file-write-unlink ...) ;; Delete files
(allow file-write* ...) ;; All write operations
(allow file-read* ...) ;; All read operations (use sparingly)
プロセス操作:
(allow process-exec* ...) ;; Execute binaries
(allow process-fork) ;; Fork child processes
(allow process-info-pidinfo) ;; Query process info
(allow signal) ;; Send/receive signals
ネットワーク操作:
(allow network-bind (local tcp "*:*")) ;; Bind to any local TCP port
(allow network-bind (local tcp "*:8080")) ;; Bind to specific port
(allow network-inbound (local tcp "*:*")) ;; Accept TCP connections
(allow network-outbound (remote ip "localhost:*")) ;; Outbound to localhost only
(allow network-outbound (remote tcp)) ;; Outbound TCP to any host
(allow network-outbound
(literal "/private/var/run/mDNSResponder")) ;; DNS via Unix socket
(allow network*) ;; All network (use sparingly)
(deny network*) ;; Block all network
IPC 操作:
(allow mach-lookup ...) ;; Mach IPC lookups
(allow mach-register ...) ;; Register Mach services
(allow ipc-posix-shm* ...) ;; POSIX shared memory
(allow ipc-posix-sem* ...) ;; POSIX semaphores
システム操作:
(allow sysctl-read) ;; Read system info
(allow sysctl-write ...) ;; Modify sysctl (rare)
(allow iokit-open ...) ;; IOKit device access
(allow pseudo-tty) ;; Terminal emulation
(allow dynamic-code-generation) ;; JIT compilation
(allow user-preference-read ...) ;; Read user defaults
既知の制限事項
- 非推奨ですが動作します:Apple は sandbox-exec を非推奨にしましたが、macOS 14 以降でも動作します
- 一時ディレクトリへのアクセスが必要になることがよくあります:多くのアプリケーションでは
/tmpと/var/foldersが必要です
例:汎用 CLI アプリケーション
(version 1)
(deny default)
;; Process
(allow process-exec*)
(allow process-fork)
(allow sysctl-read)
;; File metadata (path resolution)
(allow file-read-metadata)
;; File reads (allowlist)
(allow file-read-data
(literal "/") (literal "/var") (literal "/etc") (literal "/tmp") (literal "/private")
(subpath "/usr") (subpath "/bin") (subpath "/sbin") (subpath "/opt")
(subpath "/System") (subpath "/Library") (subpath "/dev")
(subpath "/private/var") (subpath "/private/etc") (subpath "/private/tmp")
(subpath (param "WORKING_DIR")))
;; File writes (restricted)
(allow file-write*
(subpath (param "WORKING_DIR"))
(subpath "/private/tmp") (subpath "/tmp") (subpath "/private/var/folders")
(literal "/dev/null") (literal "/dev/tty"))
;; Network disabled
(deny network*)
使用方法:
sandbox-exec -f profile.sb \
-D WORKING_DIR=/path/to/project \
-D HOME=$HOME \
/path/to/application