Claude runtime authorization
Wrap Claude tool_use blocks with Veto. Each governed tool_use block is evaluated before dispatch: allow, review, or deny, with an exportable decision record per governed decision.
The problem with Claude tool use
Claude supports tool-use agent workflows. The Anthropic SDK gives it tools, the Agent SDK gives it autonomy, and MCP gives it access to external systems. But none of these provide runtime authorization at the tool boundary. Claude decides what to do and your code executes it unconditionally.
The risk is the tool boundary. Claude can reason well and still call a tool with high-impact arguments when context is poisoned, stale, or incomplete. Sandboxing limits part of the blast radius. Enforcement decides whether the proposed action should run at all.
The Anthropic SDK's tool_use flow returns tool calls for you to execute. There is no built-in step between "Claude wants to call this" and "your code runs it."
MCP's authentication is optional. Enterprise deployments using Claude Desktop or Claude Code expose MCP tools with no centralized access control or decision records.
OWASP LLM01:2025 ranks prompt injection as the top LLM vulnerability. Constitutional AI reduces risk but cannot eliminate it. Enforcement is the defense-in-depth layer.
Before and after Veto
The left tab shows a standard Claude tool_use loop. Claude calls tools, your code executes them blindly. The right tab adds Veto. Same agent, same tools, but governed call goes through policy evaluation first.
import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic()
const tools = [
{
name: 'send_email',
description: 'Send an email',
input_schema: {
type: 'object',
properties: {
to: { type: 'string' },
subject: { type: 'string' },
body: { type: 'string' },
},
required: ['to', 'subject', 'body'],
},
},
{
name: 'delete_records',
description: 'Delete database records',
input_schema: {
type: 'object',
properties: {
table: { type: 'string' },
where: { type: 'string' },
},
required: ['table', 'where'],
},
},
]
const response = await client.messages.create({
model: process.env.ANTHROPIC_MODEL!,
max_tokens: 1024,
tools,
messages: [{ role: 'user', content: userMessage }],
})
// Claude decides to call delete_records.
// Your code executes it. No questions asked.
for (const block of response.content) {
if (block.type === 'tool_use') {
const result = await executeTool(block.name, block.input)
// No policy decision happens here.
}
}Policy configuration
Define what Claude can and cannot do in declarative YAML. Version control it alongside your code. No prompt engineering. No reliance on model cooperation.
rules:
- name: block_destructive_writes
description: Prevent DELETE/DROP on production tables
tool: delete_records
when: context.environment == "production"
action: deny
message: "Destructive writes blocked in production"
- name: approve_large_transfers
description: Human approval for transfers over $1,000
tool: transfer_funds
when: args.amount > 1000
action: require_approval
approvers: [finance-team]
message: "Large transfer requires finance team approval"
- name: block_external_email
description: Block emails to non-company domains
tool: send_email
when: "!args.to.endsWith('@approved.example')"
action: deny
message: "External emails require manual sending"
- name: read_only_queries
description: Only allow SELECT queries
tool: query_database
when: "!args.query.toUpperCase().startsWith('SELECT')"
action: deny
message: "Only read-only queries are permitted"First governed call
Install the SDK
npm install veto-sdk @anthropic-ai/sdkDefine policies
Create veto/policies.yaml with rules for each tool. Match on tool name, constrain arguments, set actions: allow, deny, or require_approval.
Validate before executing
Call veto.guard() in your tool_use handler. Check the decision. Execute only if allowed. The model, your prompts, and your model and prompt wiring stay outside the policy surface.
What Veto covers for Claude agents
Tool scoping
Allowlist which tools Claude can call per environment, user role, or time of day. Deny everything else by default. Principle of least privilege for agents.
Argument constraints
Block specific argument values: email domains, SQL statements containing DELETE, payment amounts above a threshold. Enforce at the data level, not the prompt level.
Human review
Route review-required tool calls to approval queues. Approvers get configured approval channel or email notifications with the decision context. The agent pauses until a human responds.
Decision record
Governed tool calls can log tool name, arguments, decision, reason, timestamp, and user context. Queryable via API. Exportable for SOC 2 and compliance.
Frequently asked questions
How does Claude interact with Veto policy enforcement?
Does Veto work with Claude's MCP support?
Does this add latency to Claude responses?
Does it work with streaming?
Related integrations
Make Claude tool calls enforceable.