CLAUDE LABJP
MCP — Support for the 2026-07-28 spec is rolling out across Claude. The protocol moves from bidirectional and stateful to request/response, so MCP servers can now live on serverless and edge infrastructureEXTENSIONS — Three official extensions have landed: MCP Apps for server-rendered UI, Tasks for async and long-running work, and Enterprise Managed Auth for IdP-based org-wide provisioningADOPTION — MCP passed 400 million monthly SDK downloads, roughly 4x growth this year, settling into its role as the standard way to connect agents to applicationsQUOTA — Today, August 19, is the last day of the 50 percent weekly usage boost for Claude Code subscribers. If you have long agent runs queued, this is the windowPRICING — Claude Sonnet 5's introductory rate of $2 per million input tokens and $10 output ends August 31; standard pricing of $3 and $15 takes over on September 1, twelve days outFIX — A bug where MCP v2 connections endlessly reopened subscriptions against servers with fixed timeouts is resolved, and a forward_user_identity setting was added for user attributionMCP — Support for the 2026-07-28 spec is rolling out across Claude. The protocol moves from bidirectional and stateful to request/response, so MCP servers can now live on serverless and edge infrastructureEXTENSIONS — Three official extensions have landed: MCP Apps for server-rendered UI, Tasks for async and long-running work, and Enterprise Managed Auth for IdP-based org-wide provisioningADOPTION — MCP passed 400 million monthly SDK downloads, roughly 4x growth this year, settling into its role as the standard way to connect agents to applicationsQUOTA — Today, August 19, is the last day of the 50 percent weekly usage boost for Claude Code subscribers. If you have long agent runs queued, this is the windowPRICING — Claude Sonnet 5's introductory rate of $2 per million input tokens and $10 output ends August 31; standard pricing of $3 and $15 takes over on September 1, twelve days outFIX — A bug where MCP v2 connections endlessly reopened subscriptions against servers with fixed timeouts is resolved, and a forward_user_identity setting was added for user attribution
Articles/Claude Code
Claude Code/2026-08-04Advanced

Tightening Filesystem Isolation Separately from the Network — Collect the Paths, Then Squeeze the Write Surface

Claude Code v2.1.216 lets you control filesystem isolation independently from network isolation. Before tightening anything, I traced what a real job actually touches, split reads from writes, and measured how stable the path set is across repeated runs. The numbers changed how I wrote the allowlist.

Claude Code225sandbox9security15automation101operations19

Premium Article

A week after locking down outbound traffic, I was looking at the working directory of a finished job and stopped.

There were files sitting outside the project. Network egress was fenced in, but the filesystem was still wide open. I had tightened one side and felt safe about both.

For an indie developer running unattended jobs overnight, how far writes can reach should have been one of the first values I pinned down.

Claude Code v2.1.216 made filesystem isolation controllable separately from the network side, which means the granularity can differ per use case. Changing the granularity, though, requires knowing what the job actually reaches for today.

An allowlist written from memory doesn't fail the moment you deploy it. It fails three weeks later, in the middle of the night.

So this is a field note about the reconnaissance step, not the configuration step. Most of the space goes to what I measured and what the numbers made me decide.

Realizing Only Half of It Was Fenced

For egress, I had sandbox.network.strictAllowlist in place, rejecting hosts outside the list. I wrote that work up in Locking down Claude Code sandbox egress with strictAllowlist.

One lesson stuck from that round: an allowlist assembled from memory always has holes. The host list I counted in my head turned out to be short the moment I ran anything real.

The same failure was waiting on the filesystem side, only worse. Outbound hosts number in the dozens at most. The paths a job touches run into the hundreds. That is not a set you enumerate from memory.

So I started with collection instead of configuration.

Collecting What the Job Touches

strace does the collecting. With -e trace=file it keeps only the syscalls that take a pathname, and -f follows child processes.

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

That produces raw output, not an answer. Turning 1,589 lines into something decidable means splitting reads from writes — specifically, checking whether openat was called with O_WRONLY or O_CREAT in its flags.

Here is the script I actually used. It runs as-is.

#!/usr/bin/env python3
"""Collect file access from strace output, split into read and write surfaces."""
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", ...), and friends
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"
        # Anything ending in ENOENT is a probe that missed, not a real read
        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):
    """Fold paths to a prefix of the given depth. This is your allowlist length."""
    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)
 
    # Written paths shouldn't be double-counted as reads
    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())

The job I measured mirrors a real pipeline: git init through commit, with a Node script and a Python aggregation in between. Nothing exotic — the shape most automation actually has.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Path sets from three identical runs agreed only 78.3% of the time; folded to prefixes, agreement hit 100%
175 read paths versus a write surface that folds into 3 prefixes — why tightening writes costs almost nothing
A runnable script that splits strace output into a read surface and a write surface, ready to paste
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Claude Code2026-08-05
Passing the Request, Not the Secret — Where Sandbox Credential Masking Works and Where Substitution Breaks
Claude Code's sandbox credential masking lets processes read sentinel values while a proxy swaps in the real secret at send time. I rebuilt it as a minimal proxy and measured which auth schemes survive the swap, which break, and what happens when the secret rides in the body.
Claude Code2026-07-19
A Committed Symlink That Points Outside the Worktree — Auditing Repos Before You Let AI Spin Up Parallel Trees
Claude Code 2.1.212 fixed a bug where a committed symlink under .claude/worktrees could be followed during worktree creation and write outside the repo. The patch closes the following side. Here is an audit script for the committed side, plus a quarantine workflow.
Claude Code2026-06-25
Your Sandbox Can Run the Code but Shouldn't Read Your Credentials — Shrinking the Secret-Read Surface with sandbox.credentials
Claude Code's sandbox can still read ~/.aws/credentials and token env vars by default. Using sandbox.credentials (v2.1.187+), here is how I tightened the secret-read surface of unattended runs at the OS level, with config and verification you can reuse.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →