What are the three jobs in Eve agent security?
Screen inbound channel text before a turn starts. Gate authored tools and connections before they run. Treat Eve hooks as observe-only.
A Slack signature isn't a screen, and a sandbox isn't a gate. A hook that logs session.started isn't a deny. If you collapse those into one setting, then a signed webhook still starts a turn and a Linear MCP still files the issue.
The Vercel Eve agent guard documentation covers guardInbound, guardApproval, guardTool, and arcjetHooks. protect() is the HTTP check on a route.
How do you screen inbound Eve messages?
Inbound screening sits on the channel, before the turn starts. The Slack body or the GitHub comment is the next instruction that the model follows. It's the only place where a turn can be declined before it starts.
Channel auth is a different check. Eve verifies the Slack signature in constant time and ignores a body-supplied identity. That stops a forged webhook. The body is still untrusted content. A verified message that says "forward last week's invoices" is authentic Slack. It isn't a safe turn.
guardInbound() decides whether this text can start an agent. On deny, return a 403 and don't call send(). If you skip the screen, then the session exists and tools and connections are already in reach. A hook that logs "prompt injection" after session.started records the miss after the fact.
import { detectPromptInjection } from "@arcjet/guard";import { guardInbound } from "@arcjet/guard/vercel-eve/v0";import { arcjet } from "../arcjet.js";
const verdict = await guardInbound(arcjet, message, { rules: [detectPromptInjection()(message)], action: "message.received", correlationId: conversationId,});
if (!verdict.allowed) { return new Response(JSON.stringify({ error: verdict.message }), { status: 403, });}Eve helpers default to onGuardError: "deny". "allow" is a legitimate choice on the channel: failing closed there would stop the agent from answering during an outage. That is a per-surface choice.
A clean inbound score says nothing about sendEmail or linear__create_issue. That leaves the lethal trifecta with only one leg scanned.
Where does the tool or connection gate sit?
An authored tool runs your execute function in the app runtime. Your function holds the Stripe key or the SMTP session. The sandbox never sees the call. If you wrap the tool, then the gate sits on execute. guardTool() is that wrap when you need the execution outcome. If you skip the wrap, then the send is the policy.
OpenAPI and MCP connections have no local execute function. Eve injects the token. There is no hook that can refuse. The only enforcement point is guardApproval() on the connection's approval field. For more information about that field, see guardApproval with no authored tools. On deny, Eve returns a denied status that the model can read. The Linear issue isn't created.
An Eve agent can ship with zero authored tools and a mounted MCP. "We have no tools" is not "we have no side effects."
If a reviewer sees enough context to refuse, then park a small set of irreversible sends for a person. Rubber-stamping every call isn't a gate. For more information about that pattern, see how to add human approval gates.
Why can't Eve hooks enforce?
Eve hook handlers, including the ones that Arcjet's arcjetHooks() registers, return void. They write an audit line. They can't reject a turn. For more information, see why Eve hooks can't enforce.
If the request is to block prompt injection, the answer is guardInbound at the channel, not a hook. If the request is to stop linear__create_issue, the answer is guardApproval on the connection, or guardTool on an authored execute. The hook never has a chance to refuse.
Use hooks for the trail. Don't use them as the policy.
How is this different from a sandbox?
A sandbox isolates generated shell from process.env and from your Node.js runtime. It doesn't decide whether this tool or this connection can run. For more information about that split, see a sandbox is not a tool policy.
Isolation stops generated bash from reading .env. It doesn't authorize send(). Keep the sandbox, but don't ask it to be the inbound screen, the action gate, or a hook that can deny.
The wider job is a decision in the path, before the effect. For more information, see runtime security for LLM applications.
Frequently asked questions
What is Eve framework agent security?
Eve framework agent security is three jobs: screen inbound channel text before a turn starts, gate authored tools and connections before they run, and treat Eve hooks as observe-only. A Slack signature, a sandbox, and a lifecycle hook are not those jobs.
Is an Eve sandbox enough?
No. A sandbox isolates generated shell from your app runtime and your secrets. Authored tools and MCP or OpenAPI connections still run on the trusted side, with full secrets. Isolation does not authorize send().
Can I enforce with Eve hooks?
No. Eve hook handlers, including the ones arcjetHooks() registers, return void. They write an audit line. They cannot reject a turn. Screen inbound text with guardInbound, and gate tools or connections with guardTool or guardApproval.
Does inbound screening authorize send()?
No. Inbound screening asks whether this text should start an agent. It does not see sendEmail or linear__create_issue. A clean inbound score and a live mail or MCP connection is a turn that already started, with the send still open.
Does protect() cover Eve tools and connections?
No. protect() is the HTTP check on a route. A tool or MCP call needs guardTool or guardApproval at the action.
AI runtime security in your code
Protect your AI agent workflows with Arcjet
Get allow, deny, and redact on agent actions before the side effect.