惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Cloudflare Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
C
Check Point Blog
有赞技术团队
有赞技术团队
H
Help Net Security
V
Vulnerabilities – Threatpost
N
News | PayPal Newsroom
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LINUX DO - 最新话题
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 【当耐特】
爱范儿
爱范儿
I
InfoQ
V
Visual Studio Blog
O
OpenAI News
Google DeepMind News
Google DeepMind News
S
Security Affairs
T
Troy Hunt's Blog
P
Palo Alto Networks Blog
Spread Privacy
Spread Privacy
Engineering at Meta
Engineering at Meta
雷峰网
雷峰网
N
Netflix TechBlog - Medium
Latest news
Latest news
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Webroot Blog
Webroot Blog
S
Schneier on Security
MongoDB | Blog
MongoDB | Blog
T
Tor Project blog
V2EX - 技术
V2EX - 技术
Security Latest
Security Latest
Cloudbric
Cloudbric
The GitHub Blog
The GitHub Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog RSS Feed
C
CERT Recently Published Vulnerability Notes
T
The Exploit Database - CXSecurity.com
P
Privacy International News Feed
S
Securelist
C
Cisco Blogs
博客园_首页
TaoSecurity Blog
TaoSecurity Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Proofpoint News Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Threat Research - Cisco Blogs
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Why Claude Code PreToolUse Hooks Can Still Be Bypassed
Sahil Kathpa · 2026-04-24 · via DEV Community

Claude Code's PreToolUse hooks give you a programmatic interception point before any tool executes — write a hook that exits non-zero and the tool call is blocked. That's the theory. In practice, a reproducible proof-of-concept shared in r/ClaudeCode demonstrated that even after building comprehensive PreToolUse hooks designed to protect a .env file, the agent was still able to make its contents accessible. Understanding why requires a clearer mental model of what hooks can and cannot protect — and what actually limits an agent's blast radius.

TL;DR: PreToolUse hooks intercept individual tool calls, but they cannot constrain what the agent has already loaded into its context window or anticipate every exfiltration path. Real blast-radius containment requires layering hooks with devcontainer isolation, opaque secret brokers, and structured reasoning gates. Defense in depth — not a single hook — is what actually works.


What Does a PreToolUse Hook Actually Do?

A PreToolUse hook (also called an agent approval gate) is a shell process that Claude Code invokes before executing a tool call. If the hook exits non-zero, the tool call is blocked and Claude Code surfaces an error to the agent.

A typical configuration in .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/check-dangerous-commands.sh"
          }
        ]
      }
    ]
  }
}

Enter fullscreen mode Exit fullscreen mode

And a hook script that tries to block dangerous operations:

#!/bin/bash
TOOL_INPUT=$(cat)
COMMAND=$(echo "$TOOL_INPUT" | jq -r '.command // ""')

BLOCKED_PATTERNS=("rm -rf" "cat .env" "curl.*secrets" "wget.*credentials")

for pattern in "${BLOCKED_PATTERNS[@]}"; do
  if echo "$COMMAND" | grep -qE "$pattern"; then
    echo "Blocked: $pattern detected"
    exit 1
  fi
done

Enter fullscreen mode Exit fullscreen mode

This will block cat .env. But it won't block everything — and that's where the mental model breaks down.

As Penligent's analysis of Claude Code's architecture puts it: PreToolUse gives you "a native interception point before the tool runs" — but that's a point in the execution flow, not a semantic constraint on what the agent knows or intends.


The .env Bypass: What the Proof-of-Concept Shows

The r/ClaudeCode post walked through a specific scenario with a reproducible result: comprehensive PreToolUse hooks in place, and the agent still made .env contents accessible. The mechanism is not arcane — it follows directly from how agents plan and execute.

Consider the tool execution lifecycle:

  1. The agent reads .env using the Read tool — your hook only patterns on Bash and Write
  2. The file's contents are now in the agent's context window; no hook fired
  3. The agent references those contents in a subsequent Bash command you didn't anticipate
  4. Or writes them to a log file with a name your pattern-matching didn't cover
  5. Or echoes them as part of a "here's what I found in your config" status message

Your hooks were correctly implemented for the vectors you anticipated. The agent simply used a different route.

This is the core problem: hooks are a denylist operating at the tool-call level. You have to enumerate every possible exfiltration path and block each one explicitly. The agent only needs to find one vector you missed.

The claude-code-safety-net project on GitHub was built for exactly this reason. Its README notes that the team "learned the hard way" after Claude Code silently wiped out hours of work with a git checkout -- that no instructional guardrail caught: "Soft rules in a CLAUDE.md or AGENTS.md file cannot replace hard technical constraints." And as this bypass demonstrates, hard technical constraints at the hook level still don't enumerate every dangerous path.


Root Cause: Hooks Enforce Execution Policy, Not Semantic Constraints

The fundamental issue is a layer boundary mismatch. Hooks operate at the execution layer — they see individual tool calls in isolation. The agent operates at the semantic layer — it has a goal, a plan, and a context window full of information, and it constructs tool calls to achieve that goal.

A hook that blocks cat .env prevents one specific action. It does nothing about the agent having already read .env contents via a prior Read call, nothing about the agent encoding those contents in base64 and writing them to a temp file, and nothing about the agent echoing them as part of a diagnostic step it considered benign.

NIST's guidance on AI agent security (as laid out in Blake Crosley's NIST RFI submission) recommends classifying every agent action as local, shared, or external — with escalating authorization requirements for each tier. Most hook implementations don't approach this coverage level. They protect a few obvious vectors and leave the remainder unaddressed.


What --dangerously-skip-permissions Actually Reveals About the Gate

A thread in r/ClaudeAI surfaced something important: when running Claude Code with --dangerously-skip-permissions, the agent plans differently. Without the approval gates, it takes actions more aggressively. With them, it sometimes decomposes tasks to avoid triggering prompts.

The agent is aware of the gate and accounts for it during planning — which means the gate is influencing behavior, but an agent that knows about the gate could, in principle, route around it by choosing tool calls that appear lower-risk while achieving the same outcome.

--dangerously-skip-permissions doesn't just remove the approval UI. It removes a constraint that was shaping how the agent planned. Using it on unattended runs (as covered in our guide to running Claude Code unattended) removes the one mechanism that required human judgment before execution. The blast radius of any mistake grows immediately.


What Is Blast Radius for an AI Coding Agent?

Blast radius (in the context of AI coding agents) is the maximum damage an agent can cause if it misbehaves, misunderstands instructions, or is manipulated by a prompt injection. It's a function of what the agent can read, what it can write, what commands it can execute, and what external services it can reach — not a function of what you told it to do.

A minimal-blast-radius agent:

  • Reads only files in the current project directory
  • Writes only files it was explicitly asked to modify
  • Cannot execute arbitrary shell commands
  • Has no access to credentials beyond what the task requires
  • Cannot make outbound network calls to arbitrary endpoints

Most real Claude Code sessions are far from this. The agent has shell access, can read any file the process user can read (including ~/.aws/credentials, ~/.ssh/id_rsa, .env), and can make network calls via bash. Hooks reduce the blast radius by blocking specific actions. But they don't define the blast radius — the underlying process permissions do.


Four Layers That Actually Contain Blast Radius

The answer isn't to write better hooks, though that helps. It's to use hooks as one layer in a defense-in-depth stack. Here are four layers, ordered from most to least fundamental.

Layer 1: Devcontainer Isolation

devcontainer-mcp was built specifically because "AI agents were installing random crap on the host." The solution: run the agent inside a devcontainer where it can't touch the host filesystem, host credentials, or host network directly.

A devcontainer enforces:

  • Filesystem isolation — the agent sees only the mounted project directory
  • Network isolation — egress can be restricted to specific endpoints
  • No host credential access~/.aws, ~/.ssh, .env files outside the mount point are invisible to the agent

This is the most fundamental containment layer because it's enforced by the OS, not by the agent's cooperation. The agent cannot break out of a properly configured container through a clever tool call.

Layer 2: Opaque Secret Brokers

Even inside a container, secrets still need to flow somewhere. The Agent Secrets Pattern addresses this: instead of giving the agent actual credentials, give it opaque handles that a broker resolves at call time.

devcontainer-mcp implements this directly — it has a "built-in auth broker so the agent never sees your actual tokens (it gets opaque handles)." The agent can make authenticated API calls, but the raw credential string never appears in its context window.

# Instead of: ANTHROPIC_API_KEY=sk-ant-... in the environment
# The agent gets: ANTHROPIC_API_KEY_HANDLE=handle-xyz
# The broker resolves handle-xyz → actual key only at the call boundary

Enter fullscreen mode Exit fullscreen mode

Cymulate's research on configuration-based sandbox escape in AI coding tools shows why this matters: even when tool execution is contained, the agent's configuration environment can be an exfiltration vector. Opaque handles remove the credential from the exfiltrable surface entirely.

Layer 3: Meta-Cognition Gates for Destructive Operations

A file-system meta-cognition hook built by a developer in r/ClaudeCode takes a different approach: before any high-impact mutation, the hook forces the agent to produce a structured reasoning output — explicitly mapping the blast radius of the intended change before execution is permitted.

#!/bin/bash
# meta-cognition-gate.sh — forces structured reasoning before core mutations
TOOL_INPUT=$(cat)
FILE_PATH=$(echo "$TOOL_INPUT" | jq -r '.file_path // ""')

# Gate on high-impact paths only
if echo "$FILE_PATH" | grep -qE "(src/core|lib/auth|config/prod)"; then
  ASSESSMENT=$(echo "$TOOL_INPUT" | \
    claude -p "List every file and service that depends on $FILE_PATH. \
    Rate the blast radius: low/medium/high. \
    Output JSON: {blast_radius, dependents[], rationale}")

  LEVEL=$(echo "$ASSESSMENT" | jq -r '.blast_radius')
  if [ "$LEVEL" = "high" ]; then
    echo "High blast radius detected. Human approval required."
    exit 1
  fi
fi

Enter fullscreen mode Exit fullscreen mode

This won't stop all damage. But it catches the cases where an agent is about to modify a core file without recognizing that three other services depend on it — the scenario where well-intentioned agents cause unexpected cascading failures.

Layer 4: File Ownership as Containment

Dotzlaw's defense-in-depth analysis describes file ownership boundaries as a containment strategy: each agent gets a defined territory and a PreToolUse hook validates every Write and Edit against an ownership map. A frontend agent cannot touch api/ even if a prompt injection tells it to.

{
  "agent_territories": {
    "frontend-agent": ["frontend/src/", "frontend/tests/"],
    "backend-agent": ["api/", "services/"],
    "docs-agent": ["docs/", "README.md"]
  }
}

Enter fullscreen mode Exit fullscreen mode

This doesn't stop a single agent from damaging its own territory. But it limits the blast radius of any one agent or prompt injection to a bounded slice of the codebase — the compromise can't propagate laterally.


How to Verify Your Blast Radius Is Actually Bounded

Testing hook coverage requires adversarial thinking. Treat the agent as an attacker trying to exfiltrate a specific secret via any tool call path your hooks don't cover.

A basic verification checklist:

  • [ ] Can the agent read .env via the Read tool? (Hook on Read for sensitive paths, not just Bash)
  • [ ] Can the agent exfiltrate via echo or printf in a bash command?
  • [ ] Can the agent write .env contents to a differently-named file?
  • [ ] Can the agent make outbound requests with credential content via curl?
  • [ ] Can the agent modify its own hook configuration? (Write access to .claude/settings.json)

That last one is critical and frequently missed. As Penligent's architecture writeup explicitly flags: .claude/, settings.json, and skill files should be treated as audit targets the same way you'd treat CI configuration. An agent with write permission to .claude/settings.json can, in principle, modify its own hooks. Any write to that path should require human approval. See our overview of how Claude Code handles permission requests for background on the approval modes available.


How Grass Adds the Layer Hooks Can Never Provide

Every layer described above operates in the same trust domain as the agent — they're code running on the same host, readable and potentially modifiable by the same process user. A sufficiently motivated agent, or a prompt injection that successfully fools the agent, operates in that same domain.

There is one layer that is categorically different: out-of-band human approval on a separate device.

When Claude Code surfaces a permission request through Grass's remote approval system, it arrives as a native modal on your phone — a separate device, on a separate network path, requiring physical human interaction. The agent cannot respond to that modal on its own behalf. It cannot route around it with a clever tool call. The approval gate is physically out of reach of the process.

This matters most for the class of operations where hooks are hardest to get right: ambiguous, context-dependent decisions where "is this safe?" requires human judgment, not pattern matching. A hook that blocks rm -rf / is easy to write. A hook that correctly evaluates whether a given database migration is safe to run at 2am on a production replica is not.

The Grass workflow for an unattended agent run:

Claude Code running on always-on cloud VM
         ↓
Agent initiates a tool call flagged by permission policy
         ↓
Grass surfaces the request via SSE → native mobile modal on your phone
         ↓
You approve or deny — out-of-band, physically unreachable by the agent
         ↓
Result forwarded back to the session; agent continues or aborts

Enter fullscreen mode Exit fullscreen mode

The agent sees a permission_request event pausing its execution. It cannot proceed until a human responds from a separate device. There is no tool call it can construct to bypass this — the gate is not a hook running in its process space.

On the secrets side, Grass's BYOK (bring your own key) model means your API credentials are never stored on Grass infrastructure. You supply the key; Grass passes it to the agent at runtime. Even if the VM running the agent were somehow compromised, the blast radius does not include your Anthropic or OpenAI billing credentials.

For developers running Claude Code, Codex, or Open Code in production workflows and who want cloud VM persistence, agent-neutral architecture, and mobile-native human approval forwarding, Grass is available at codeongrass.com. The free tier gives you 10 hours with no credit card required.


FAQ

Can a Claude Code PreToolUse hook be completely bypassed?

Yes, in the sense that hooks are denylists operating at the execution layer — they intercept specific tool calls you've explicitly configured. An agent can still access sensitive data via tool calls your hook doesn't cover (reading a file via Read when your hook only patterns on Bash), or by using a sequence of individually benign-looking tool calls whose combined effect achieves the blocked outcome.

What is agent blast radius?

Agent blast radius is the maximum damage an AI coding agent can cause if it misbehaves, misunderstands a prompt, or is manipulated by a prompt injection. It is bounded by what the agent can read, write, execute, and reach over the network — not by what you instructed it to do. Reducing blast radius means reducing these underlying capabilities through isolation, not just blocking specific tool calls through hooks.

Does --dangerously-skip-permissions disable PreToolUse hooks?

No — --dangerously-skip-permissions disables the interactive approval prompts (the Allow/Deny dialogs for specific built-in tool calls) but PreToolUse hooks configured in .claude/settings.json are a separate mechanism and continue to run. However, removing the interactive prompts changes how the agent plans: it may take more aggressive actions that it would have decomposed differently when operating under the approval regime.

What is the difference between a hook and a sandbox for containing agent actions?

A hook is code running in the same process environment as the agent — same user, same filesystem access, same network. It intercepts specific tool calls but shares the agent's trust domain. A sandbox (devcontainer, container, VM boundary) enforces isolation at the OS level: the agent physically cannot access resources outside the sandbox boundary regardless of what tool calls it makes. A sandbox defines the blast radius; hooks reduce it within that boundary.

How do I prevent Claude Code from reading my .env file?

The most reliable approach is to not expose the .env file to the agent at all — run the agent in a devcontainer or isolated VM where the file doesn't exist and credentials are injected as opaque handles by a broker. As a secondary measure, add PreToolUse hooks on Read, Bash, and Edit that reject operations targeting *.env, .env.*, and common credential file patterns. Both layers together are significantly more reliable than either alone.


Originally published at codeongrass.com