CLAUDE LABEN
COWORK — Cowork が web・iOS・Android へ広がり、セッションとファイルがデバイスを跨いで追随するようになりました。ベータの利用上限倍増は8月5日までですAPPROVE — 承認をモバイルから返せるようになりました。バックグラウンド実行とスケジュールタスクで「許可待ちのまま止まっていた」時間が縮みますSANDBOX — v2.1.216 でファイルシステムの分離をネットワーク側と切り離して制御できるようになりました。用途ごとに粒度を変えられますA11Y — v2.1.208 でスクリーンリーダーに対応し、vim insert mode のリマップ(jj で抜ける等)が入りましたSTREAM — サブエージェントの出力が逐次流れるようになりました。長時間の委譲でも進行が見え、バックグラウンドエージェントの信頼性も上がっていますPRICE — Sonnet 5 のプロモ価格 $2/$10 per Mtok は8月31日までです。9月1日から標準価格の $3/$15 per Mtok に移りますCOWORK — Cowork が web・iOS・Android へ広がり、セッションとファイルがデバイスを跨いで追随するようになりました。ベータの利用上限倍増は8月5日までですAPPROVE — 承認をモバイルから返せるようになりました。バックグラウンド実行とスケジュールタスクで「許可待ちのまま止まっていた」時間が縮みますSANDBOX — v2.1.216 でファイルシステムの分離をネットワーク側と切り離して制御できるようになりました。用途ごとに粒度を変えられますA11Y — v2.1.208 でスクリーンリーダーに対応し、vim insert mode のリマップ(jj で抜ける等)が入りましたSTREAM — サブエージェントの出力が逐次流れるようになりました。長時間の委譲でも進行が見え、バックグラウンドエージェントの信頼性も上がっていますPRICE — Sonnet 5 のプロモ価格 $2/$10 per Mtok は8月31日までです。9月1日から標準価格の $3/$15 per Mtok に移ります
記事一覧/Claude Code
Claude Code/2026-08-04上級

ファイルシステムの分離をネットワークと別に締める — 触ったパスを採り、書き込み面から絞る

Claude Code v2.1.216 でファイルシステムの分離をネットワークと切り離して指定できるようになりました。締める前にジョブが触ったパスを strace で採取し、読み取り面と書き込み面を分けて測った実務メモ。同じジョブを3回走らせたときのパス集合の安定率と、接頭辞に畳んだときの安定率の差まで実測しています。

Claude Code210サンドボックス7セキュリティ16自動化75運用設計20

プレミアム記事

外向きの通信を許可リストで締めた翌週、走り終えたジョブの作業ディレクトリを眺めていて手が止まりました。

プロジェクトの外にあるディレクトリに、いくつかファイルが増えていたのです。通信は絞ったのに、ファイルシステムは既定のまま開いていました。片側だけ締めて安心していたことになります。

個人開発で夜間に無人実行を回している以上、書き込みの届く範囲は本来まっさきに決めておくべき値でした。

Claude Code v2.1.216 で、ファイルシステムの分離をネットワーク側と切り離して指定できるようになりました。用途ごとに粒度を変えられる、という変更です。ただ粒度を変えるには、いま実際にどこまで触っているのかを先に知る必要があります。

推測で書いた許可リストは、締めた瞬間ではなく、三週間後の深夜に牙を剥きます。

この記事は、締める前の採取に絞った実務メモです。設定の書き方そのものより、何を測って、その数字から何を決めたかに紙幅を割きます。

片側だけ締めていた、という気づき

ネットワーク側については、sandbox.network.strictAllowlist を入れて許可リスト外のホストを拒む形にしていました。この作業の経緯はstrictAllowlist で Claude Code サンドボックスの外向き通信を締めるにまとめています。

そのときに得た教訓が一つあります。許可リストは推測で書くと必ず穴が開くということです。ホスト名を頭で数えて書いた許可リストは、実際に走らせると足りませんでした。

同じことがファイルシステム側でも起きるはずでした。むしろ、こちらのほうが厄介です。通信先のホストは多くても数十ですが、ジョブが触るパスは数百に及びます。頭で数えられる規模ではありません。

そこで、設定を書く前に採取から始めることにしました。

触ったパスを採る

採取には strace を使います。-e trace=file を付けると、パス名を引数に取るシステムコールだけを拾えます。-f で子プロセスも追跡します。

strace -f -e trace=file -o trace.log bash job.sh

これで生ログは取れますが、そのままでは読めません。1,589行の出力から、読み取り面と書き込み面を分けて集計する必要があります。分けたいのは、openat のフラグに O_WRONLYO_CREAT が立っているかどうかです。

以下は実際に使ったスクリプトです。そのまま貼れば動きます。

#!/usr/bin/env python3
"""strace の出力からファイルアクセスを採取し、読み取り面と書き込み面に分ける。"""
import re, sys, os, json, collections
 
# openat(AT_FDCWD, "/path", FLAGS...) = fd
OPENAT = re.compile(r'openat\(([^,]+),\s*"([^"]*)",\s*([^)]*)\)\s*=\s*(-?\d+)')
# stat("/path", ...) / access("/path", ...) など
PATHCALL = re.compile(
    r'\b(stat|lstat|newfstatat|access|readlink|unlink|unlinkat|mkdir'
    r'|mkdirat|rename|renameat2?|statx|execve)\((?:[^,]+,\s*)?"([^"]*)"')
 
WRITE_FLAGS = ("O_WRONLY", "O_RDWR", "O_CREAT", "O_TRUNC", "O_APPEND")
MUTATORS = {"unlink", "unlinkat", "mkdir", "mkdirat",
            "rename", "renameat", "renameat2"}
 
def classify(line):
    m = OPENAT.search(line)
    if m:
        _, path, flags, ret = m.groups()
        kind = "write" if any(f in flags for f in WRITE_FLAGS) else "read"
        return path, kind, int(ret) >= 0
    m = PATHCALL.search(line)
    if m:
        call, path = m.groups()
        kind = "write" if call in MUTATORS else "read"
        # ENOENT で終わったものは「探索の空振り」として区別する
        ok = not re.search(r'=\s*-1\s+ENOENT', line)
        return path, kind, ok
    return None
 
def normalize(p, cwd):
    if not p.startswith("/"):
        p = os.path.join(cwd, p)
    return os.path.normpath(p)
 
def compact(paths, depth=3):
    """パスを深さ depth の接頭辞に畳む。許可リストの行数はこの数で決まる。"""
    out = collections.Counter()
    for p in paths:
        parts = [x for x in p.split("/") if x]
        out["/" + "/".join(parts[:depth])] += 1
    return out
 
def main(trace_path, cwd):
    reads, writes, misses = set(), set(), set()
    with open(trace_path, errors="replace") as fh:
        for line in fh:
            r = classify(line)
            if not r:
                continue
            path, kind, ok = r
            path = normalize(path, cwd)
            (writes if kind == "write" else reads).add(path)
            if not ok:
                misses.add(path)
 
    # 書き込んだパスは読み取り面から差し引く(二重計上を避ける)
    reads -= writes
    misses -= writes
 
    print(json.dumps({
        "read_paths": len(reads - misses),
        "probe_misses": len(misses),
        "write_paths": len(writes),
        "read_prefixes_d2": len(compact(reads - misses, 2)),
        "read_prefixes_d3": len(compact(reads - misses, 3)),
        "write_prefixes_d3": len(compact(writes, 3)),
        "write_prefix_list": sorted(compact(writes, 3)),
    }, indent=2, ensure_ascii=False))
 
if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else os.getcwd())

計測対象にしたのは、実際の自動化に近い構成のジョブです。git init からコミットまで、途中で Node のスクリプトと Python の集計を挟みます。特別なことは何もしていない、ごく普通のパイプラインです。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
同じジョブ3回で採ったパス集合の安定率は78.3%、接頭辞に畳むと100%。許可リストを接頭辞で書くべき実測根拠
読み取り175パスに対し、書き込みは接頭辞3行に収まった。書き込み面から締めると影響範囲が小さい理由
strace 出力を読み取り面と書き込み面に分けて採取する実行可能なスクリプト(そのまま貼って動きます)
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

Claude Code2026-07-25
strictAllowlist で Claude Code サンドボックスの外向き通信を締める
Claude Code v2.1.219 の sandbox.network.strictAllowlist で自動化の外向き通信を締めた実践メモ。接続先を洗い出すスクリプト、失敗までの時間で拒否とDNSと回線を切り分ける実測、許可リストをホスト名で書くべき理由まで。
Claude Code2026-08-03
存在チェックが通っても書けない — 無人実行の前提を能力プローブで測る
ディレクトリが存在することと、そこへ書けることは別です。無人で走る Claude Code のセッションが静かに止まる原因を実測し、能力プローブ方式のプリフライトを設計した記録です。
Claude Code2026-07-30
作業ルートを途中で足したとき、無視規則と deny はどこまで届くのか — DirectoryAdded で境界を測り直す
セッション途中で作業ルートを追加すると、無視規則も deny パターンもそのままでは新しいルートに届きません。git check-ignore と照合器の比較で境界を実測し、DirectoryAdded から呼ぶ差分監査スクリプトの実行結果まで記録しました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →