Inference hooks: how to block a Claude prompt before the model ever sees it
In brief
Anthropic shipped Inference hooks in beta for Claude Enterprise on August 5, 2026. Every governed prompt across claude.ai, Cowork, and Claude Code is sent to a server your organization runs, which returns allow or deny before inference starts. Here is what it inspects, what it cannot see, and how to roll it out without blocking people on day one.
Contents
Anthropic launched Inference hooks in beta for Claude Enterprise on August 5, 2026.
The mechanism is simple. When someone in your organization submits a prompt, Anthropic sends the conversation transcript to an HTTPS endpoint you run — Anthropic calls it your AI security server — and waits. Your server replies allow or deny. A denied request never reaches the model.
That single sentence is the whole feature, and it closes a gap that has bothered security teams since the first enterprise Claude rollout: until now, every control was either on the user's device (bypassable) or after the fact (too late).
Where this sits relative to the Compliance API
Anthropic already gives Enterprise admins the Compliance API, which retrieves activity, chats, files, and projects for audit and export. Inference hooks are the other half of the clock:
| Inference hooks | Compliance API | |
|---|---|---|
| When it acts | Inline, before inference runs | After the fact |
| What it does | Allows or denies each request in real time | Retrieves what already happened |
| Who calls whom | Anthropic calls your server | You call Anthropic's API |
If your security review asked "can we stop a prompt containing card data from ever reaching a model," the answer changed on August 5.
What your server actually receives
Anthropic POSTs a JSON object. The important thing for a policy conversation is what is in it and what is not.
In it: the transcript as the user sees it — text, tool calls and their results, text extracted from attachments, and prior turns. Plus actor (user id and email address when available), source.application (claude-ai or claude-code today), model, session_id, and a request_id for correlation.
Not in it: system prompts, tool definitions, Anthropic-internal context, Claude's hidden reasoning, and raw file or image bytes. Attachments arrive as metadata plus extracted text.
A trimmed example of the request body:
{
"type": "prompt",
"request_id": "req_abc123",
"actor": {
"type": "user",
"id": "user_01AbCdEfGhIjKlMnOpQrStUv",
"email_address": "alice@example.com"
},
"source": { "application": "claude-ai" },
"model": "claude-opus-5",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "Summarize the attached report." },
{
"type": "attachment",
"file_name": "q2-report.pdf",
"media_type": "application/pdf",
"size_bytes": 48213,
"text": "Q2 revenue grew 14% quarter over quarter..."
}
]
}
]
}
Your server answers with HTTP 200 and a two-field object:
{ "action": "allow" }
or
{
"action": "deny",
"deny_reason": "This prompt appears to contain customer payment card data, which your organization's policy does not allow.",
"reference_id": "scan_01HXPT4R9V"
}
deny_reason is shown to the user, truncated at 500 characters, followed by a standing message your admins configure (who to contact, how to request an exception). reference_id is never shown to the user — it lands on the inference_hooks_request_denied entry in the compliance Activity Feed so you can join a block back to the scan record in your own system.
The five details that will bite you
1. A non-200 response is not a deny. Anything other than HTTP 200 with a parseable verdict is a webhook failure, and failure handling takes over instead. If your scanner errors out and you were relying on "errors mean block," you will get whatever your org's failure-handling setting says — which may be allow.
2. Bodies go up to 10 MB. Transcripts are sent untruncated. nginx defaults client_max_body_size to 1 MB and Express's express.json() defaults to 100 kB. A rejected body counts as a webhook failure, so under Allow the request failure handling, your longest and most sensitive conversations are exactly the ones that sail through uninspected. Raise the limit before you enforce.
3. Verify the signature over raw bytes. Requests are signed per the Standard Webhooks spec using webhook-id, webhook-timestamp, and webhook-signature headers — an HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw body}. Two bugs cause most failures: computing the HMAC after JSON round-tripping the body, and decoding the signing secret with a URL-safe base64 decoder. The secret uses the standard alphabet, so + and / appear regularly and a URL-safe decoder silently derives the wrong key.
Here is the verification in TypeScript, standard library only:
import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_SECONDS = 300;
export function verify(secret: string, headers: Record<string, string>, body: Buffer): boolean {
const id = headers["webhook-id"];
const ts = headers["webhook-timestamp"];
const sigs = headers["webhook-signature"];
if (!id || !ts || !sigs) return false; // unsigned: not from Anthropic
const signedAt = Number(ts);
if (!Number.isFinite(signedAt) || Math.abs(Date.now() / 1000 - signedAt) > TOLERANCE_SECONDS) {
return false; // replayed, or the clocks disagree
}
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64"); // standard alphabet
const payload = Buffer.concat([Buffer.from(`${id}.${ts}.`), body]); // raw bytes
const expected = Buffer.from("v1," + createHmac("sha256", key).update(payload).digest("base64"));
return sigs.split(" ").some(candidate => {
const bytes = Buffer.from(candidate);
return bytes.length === expected.length && timingSafeEqual(bytes, expected);
});
}
4. Every governed request pays your round trip. The verdict timeout is configurable from 1 to 10,000 ms and defaults to 5,000 ms, covering connection, TLS handshake, request, and response. Whatever your scanner takes, every person in the organization waits for it on every message. Load-test before a wide rollout.
5. Sustained failures trip a circuit breaker. If your server keeps failing, Anthropic stops calling it and failure handling applies to everything. Recovery is manual: fix the server, then have an admin turn Enforce verdicts back on. Nobody gets paged automatically.
How to roll it out without a bad Monday
The configuration has three dials that exist specifically so you do not have to flip enforcement on for everyone at once:
- Shadow mode — your server sees live traffic and returns verdicts, and nothing is blocked. Run here until your false-positive rate is boring.
- Rollout percentage — inspect a chosen fraction of requests.
- Role exclusions — exempt members of chosen roles entirely.
A sane sequence: stand up an always-allow server, run Test connection, add signature verification, go to shadow mode for a week and count what would have been blocked, tune, then enforce at 10% and climb.
Pick your failure handling deliberately. Block the request means an outage in your scanner is an outage in Claude for the whole company. Allow the request means an outage in your scanner is a silent hole in your DLP. Most organizations start at allow, in shadow mode, and revisit once the server has a track record.
What it does not cover
- Image-only content is not inspected. Raw bytes are never sent, so a screenshot of a document passes through as metadata and nothing else. If your policy concern is people pasting screenshots of regulated data, this does not solve it.
- Verdicts are allow or deny only. There is no rewrite or redact.
- Voice mode is not covered.
- Platform organizations are out of scope — this governs claude.ai, Cowork, and Claude Code, not raw Claude API access.
- Not available on Amazon Bedrock or Google Cloud.
That last set matters for the business case. Inference hooks govern the surfaces where employees type, not the surfaces where your engineers build. If your risk is a developer's application sending customer data to the API, this is the wrong control — you want request-side controls in your own application.
The other Enterprise security control that shipped this week
On August 6, Anthropic added skill and plugin security scanning in beta for Enterprise plans: third-party skills and plugins are automatically checked for malicious content when someone uploads or edits them. Different problem, same theme — the enterprise controls are moving from "audit what happened" toward "check it at the door." If you are writing the security section of a Claude rollout plan, these two now belong in it together.
Try this today
Write down the one prompt you most do not want an employee to send. Then answer three questions: would the transcript Anthropic sends actually contain the thing you are worried about (remember: no raw bytes, no system prompts)? Would your existing DLP scanner catch it in plain text? And if your scanner were down for an hour, would you rather Claude stop working or that prompt go through? Those three answers are your configuration.
Related reading
- Claude Compliance API — the after-the-fact half of the same job
- What's new in Claude admin controls — groups, spend limits, managed Code policies
- Security and privacy for Claude admins — the baseline before you add hooks
- Claude Team vs. Enterprise for IT — which plan gets which control
Sources: Inference hooks and Develop an Inference hooks integration, Anthropic, August 5, 2026.