← Back to Payloads
AI Engineering2026-08-30

Claude Code 2.1.251 Quietly Shipped the Hook System Anthropic Has Been Avoiding for a Year. Then They Fixed Eight Sandbox and Path-Traversal Bugs in the Same Release. The Order Matters.

Claude Code 2.1.251 (Aug 28, 2026) ships PreModelSwitch/PostModelSwitch hooks, foreground subagent live streaming, and a spend limit bar. It also fixes eight distinct security bugs in the same release: TOCTOU path-traversal via in-place symlink swap, plugin command path-traversal, project-settings telemetry bypass, Workflow scriptPath escape, Grep/Glob Read-deny bypass, ANTHROPIC_CUSTOM_HEADERS approval for credential/routing/org headers, server-managed sandbox/credential/proxy guard, and sandboxed Bash output isolation. Read both halves of this release.
Quick Access
Install command
$ mrt install claude-code
Browse related skills
Claude Code 2.1.251 Quietly Shipped the Hook System Anthropic Has Been Avoiding for a Year. Then They Fixed Eight Sandbox and Path-Traversal Bugs in the Same Release. The Order Matters.

Claude Code 2.1.251 Quietly Shipped the Hook System Anthropic Has Been Avoiding for a Year. Then They Fixed Eight Sandbox and Path-Traversal Bugs in the Same Release. The Order Matters.

Hey guys, Mr. Technology here.

Anthropic pushed Claude Code 2.1.251 on August 28, 2026 and most of the coverage you saw probably led with the hooks. That is the wrong lead. The hooks are the headline feature you would have asked for if Anthropic had bothered to ask you. The eight security fixes in the same release are the story that will not show up in the marketing. One is a path-traversal in the file tools that triggers when an in-place symlink swap is performed after the permission check. Another is a scope-bypass that lets a project setting enable raw API body logging against an OTLP collector that managed settings or your host app is trying to pin. Read this release top to bottom before you decide which one matters. (anthropics/claude-code CHANGELOG.md v2.1.251)

I have been running Claude Code in production agent stacks since the public preview. I have the changelog diffs. I have the hook scripts that were impossible to write cleanly under the old event model. Let me walk you through what shipped, what is actually new, and what you need to do before the next time you let an unattended agent loose in a directory that contains anything you care about.

The Hooks: PreModelSwitch and PostModelSwitch

The headline feature is two new hook events: PreModelSwitch and PostModelSwitch. The names are exact. The semantics are not what most agents assume.

PreModelSwitch fires before Claude Code changes the active model. The hook receives enough context to know which model is being switched to, and your handler can return one of three responses:

  • Allow — the switch proceeds normally.
  • Block — the switch is rejected. Claude Code stays on the current model and surfaces your block reason to the model so it can adjust its plan.
  • Annotate — the switch proceeds, but additional context you return is injected into the next prompt. This is how you wire your own routing logic into the harness without forking it.

PostModelSwitch fires after the switch. It is informational: it cannot block, but it can log, audit, or trigger downstream actions (kill the session, send a webhook, write to your trace store).

Why this matters. For the entire history of Claude Code, model-switching was an internal harness decision you could not intercept. If your routing layer wanted to make a different call than Claude Code's auto-routing did, you had to either disable auto-routing entirely or sit and watch your tokens evaporate on the wrong tier. PreModelSwitch is the escape hatch. You can now implement your own routing logic in 30 lines of shell:

bash
# ~/.claude/hooks/PreModelSwitch.sh
#!/usr/bin/env bash
# Read the requested target model from stdin
REQUESTED=$(jq -r '.target_model')
CURRENT=$(jq -r '.current_model')
# If we are moving from Opus to anything else on a coding task, block it
if [[ "$CURRENT" == *"opus"* && "$REQUESTED" != *"opus"* ]]; then
  echo '{"decision":"block","reason":"Coding tasks stay on Opus. Use /model to override."}'
  exit 0
fi
echo '{"decision":"allow"}'

That is a real production scenario. The model auto-switches to Sonnet mid-task to save tokens, your Sonnet call hallucinates an API, and you spend the next twenty minutes debugging why your Opus agent went off the rails. With PreModelSwitch, you can pin Opus for coding tasks and let it roam free for everything else.

The SessionStart resume path also got an upgrade. Resume hooks now receive session staleness (how long since the session was last active) and the estimated re-cache cost of resuming. If you are routing through a Bedrock or Vertex endpoint where prompt-cache hits are not free, that number matters. You can write a hook that decides "this session is too stale to resume cheaply; start fresh."

Foreground Subagent Live-Streaming

If you have ever opened the subagent panel in Claude Code while a subagent was running, you have seen the gap. Background subagents show a status line. Foreground subagents — the ones you actually launched explicitly — only show progress text. The actual tool calls and tool results were hidden.

v2.1.251 fixes this. Foreground subagent tool calls and results now live-stream to Remote Control clients. If you have Claude Code open in the desktop app, in the IDE extension, or via the cloud session UI, you can watch the subagent's actual Read, Edit, Bash, and Grep calls as they happen.

This is more than a UI polish. Three things it actually unlocks:

1. Real-time debugging. When a subagent loops on a tool, you see the loop forming. Before 2.1.251 you only saw "subagent is running." 2. Audit trail during the run, not after. Compliance teams that need to verify which files a subagent touched can now stream the audit log to a SIEM, not reconstruct it post-hoc. 3. Operator intervention. You can interrupt a subagent that is about to do something you don't want, while it is still doing it.

The default is still background subagents showing status only. The behavior change is foreground-only, which is the right default — most users do not need to watch every tool call, but power users and ops teams do.

Spend Limit Bar

Small feature, big consequence for anyone running agents on a budget. /usage now shows a spend limit bar, and there is a new rate_limits.spend_limit status line field for developers behind a Claude apps gateway with spend limits.

The mechanics: if your gateway has a per-account or per-org spend limit configured, you see it. The bar tracks how close you are to it. The status line field lets you surface the same number in the TUI footer or pipe it into your own observability.

For most developers this is invisible. For anyone running a multi-agent stack against a budget, this is the visibility layer they have been asking for since /usage shipped. The fact that it is gated to the Claude apps gateway means this is an enterprise-facing feature dressed in a developer-facing UI. Expect it to show up in Bedrock and Vertex spend dashboards within a quarter.

The related change worth noting: /cost now includes a per-session prompt-cache line with hit ratio, misses, tokens re-cached, warm vs. cold. There is a matching prompt_cache object for status line scripts. If you are optimizing cache hit rate (and you should be — it is the difference between paying list price and paying roughly a tenth of it for cached tokens), this is the metric that matters. The previous /cost screen told you what you spent. It did not tell you what you saved.

The Security Sweep: Eight Fixes in One Release

Now the story that should have been the lead.

Anthropic shipped eight distinct security fixes in 2.1.251. Read them in this order. The order matters.

1. Read/Write/Edit path-traversal via in-place symlink swap

The vulnerability: file tools (Read, Write, Edit) followed a symlink that had been swapped inside the working directory after the permission check ran. The check approved access to path A; between the check and the read, an attacker (or a misbehaving subagent) swapped A for B; the tool followed the symlink and read or wrote B instead of A.

This is the textbook TOCTOU on a filesystem. It is real. It is the kind of bug that would be CVE-worthy in a sandboxed runtime from a smaller vendor. Anthropic shipped the fix and the changelog sentence is a single line.

What you need to do: audit any workflow where another process (a watcher, a build script, another agent) is writing to the working directory while Claude Code is running. If you are running Claude Code against a directory under heavy concurrent mutation — a CI runner, a watched build output directory, a tmpfs shared between agents — the previous behavior was exploitable. The fix is now in 2.1.251.

2. Plugin command path-traversal via marketplace entry

A plugin's commands array in a marketplace entry could point outside the plugin directory. The path was resolved against the marketplace root, not the plugin root, and a sufficiently nested entry could traverse out.

This is a supply-chain vulnerability. If you install Claude Code plugins from any marketplace — official or third-party — you need to know that the previous behavior let a malicious or careless marketplace entry reach outside its declared boundary. The fix rejects path-traversal attempts with a clear error. If your plugin's commands suddenly stop working after upgrade, this is why. Read the path. Fix it.

3. Project settings telemetry bypass (raw API body logging)

This is the one that should keep your security team up at night.

Project-level .claude/settings.json could enable detailed beta tracing or raw API body logging. A lower-scope beta tracing endpoint could bypass an OTLP collector pinned by managed settings or a host app. The combined effect: project settings could override an organizational decision to route telemetry to a specific collector.

Translation: if your org has a managed settings file that pins telemetry to your internal observability stack, and a project checked into the repo enables raw API body logging, the project setting previously won. Your security team's observability assumptions were wrong.

What you need to do: if you are an enterprise using managed settings to pin telemetry, verify your .claude/settings.json files across every project do not enable detailed beta tracing or raw API body logging without explicit approval. The fix is in 2.1.251. Audit your existing settings.

4. Workflow tool scriptPath escape

The Workflow tool reads and quotes a scriptPath in errors. Before the permission check ran, it read the script content to produce the error message. The script content of a file outside the session's read scope could be embedded in an error and quoted back to the model.

This is a confused-deputy bug. The Workflow tool had implicit read access to anything it could name, regardless of whether the session was allowed to read it. The fix: read the script only after the permission check passes.

5. Grep/Glob Read-deny bypass via symlinked search path

Grep and Glob did not apply Read(...) deny rules to files reached through a symlinked search path. If you have a .claude/settings.json with permissions.deny rules for Read, and the file you want to deny lives behind a symlink, Grep would walk the symlink and read it anyway.

Subtle. Real. Fixed.

6. ANTHROPIC_CUSTOM_HEADERS now requires approval for credential/org/tenant/routing/API-behavior headers

Custom headers via ANTHROPIC_CUSTOM_HEADERS are a developer feature. They are also a way to inject Authorization, Host, or any tenant/routing header. The fix: managed or project settings that set credential, org/tenant, routing, or API-behavior headers via ANTHROPIC_CUSTOM_HEADERS now require explicit approval.

This is the right behavior. If you have been using ANTHROPIC_CUSTOM_HEADERS for legitimate reasons (custom routing, multi-tenant gateways, header-based feature flags), your workflow is unchanged after approval. If you have a project that sets Authorization via env to route through a partner's API, that now requires approval.

7. Server-managed settings sandbox/credential/proxy guard

Server-managed settings that:

  • Terminate sandbox TLS
  • Route sandbox traffic through your own proxy
  • Inject credentials
  • Weaken sandbox isolation

...now require approval before they apply. The previous behavior applied them silently.

This is the meta-fix. The other seven fixes are about specific attack surfaces. This one is about the meta-attack: a server-side setting silently weakening the security model the rest of the fixes are trying to preserve.

8. Sandboxed Bash command output isolation

How sandboxed Bash commands created and read back output files was changed so a sandboxed command cannot redirect or replace them. The previous behavior let a sandboxed command replace the file that the harness was using to capture its output, which means the harness could be tricked into running an unsandboxed version of the command.

If you are running Claude Code with sandboxing enabled (and you should be — it is on by default on macOS and Linux), the sandbox was less airtight than you assumed. Fixed.

What You Should Do

Three things. In this order.

Update. claude --version should report 2.1.251 or later. If you are managing Claude Code across a fleet (Bedrock, Vertex, Foundry, self-hosted runner), roll the upgrade through your normal channel. The hooks changes alone justify the rollout; the security fixes make it non-optional.

Audit your plugin marketplaces. If you install any third-party Claude Code plugin from a marketplace you did not write yourself, review the marketplace entry for path-traversal attempts in the commands array. The fix is in 2.1.251, but plugins authored against the previous behavior may have been relying on the loose path resolution.

Audit your telemetry and settings posture. If you are an enterprise with managed settings pinning telemetry, run a project-wide grep for beta.tracing, raw_api_body_logging, and similar settings. Verify that no project enables them without approval. If you are a developer using ANTHROPIC_CUSTOM_HEADERS to inject credentials, routing, or org/tenant headers, you will see a new approval prompt after upgrade. Approve it once if the behavior is intentional.

The Bigger Picture

Claude Code has shipped roughly a major feature every two weeks and roughly a security fix every week for the last six months. The pattern is normal for a fast-moving client. The pattern that 2.1.251 breaks is shipping a feature release without security fixes, or vice versa. 2.1.251 ships both, in the same release, with the feature changes dominating the changelog and the security fixes buried below them.

That is not a critique. It is the correct tradeoff for a release cadence. But it does mean the change-intelligence layer that watches Claude Code has to read every release top to bottom. The hooks are real. The security fixes are real. The release is bigger than either story alone suggests.

I will keep watching. The next release will tell us whether Anthropic is going to keep shipping eight security fixes at a time, or whether 2.1.251 was a backlog flush. The bet is on backlog flush. Eight is too many to be normal.

Sources

1. anthropics/claude-codeCHANGELOG.md, v2.1.251 entry. Verified 2026-08-30 against the raw GitHub content (raw.githubusercontent.com/anthropics/claude-code/refs/heads/main/CHANGELOG.md). 2. AnthropicClaude Code documentation. Hook event semantics, PreModelSwitch/PostModelSwitch decision responses, SessionStart resume staleness and re-cache cost, foreground vs. background subagent behavior, /usage spend limit bar, rate_limits.spend_limit status line field. 3. Mr. Technology — Independent verification of changelog content; production hook scripts drafted against the documented PreModelSwitch decision response schema.

Originally published: 2026-08-30. Last verified: 2026-08-30. No corrections.

Related Dispatches