AI tool callbacks often arrive as webhooks. The model asked your app to call a vendor. The vendor finishes later and posts a result to your URL. If that URL accepts any POST, an attacker can fake a success, inject a tool result into the next prompt, or trigger a write the user never approved.
Signing webhooks is how you prove the callback came from the party you called. Verification belongs on your server before any tool result touches the model or the database.
What to sign and verify
Require a shared secret or asymmetric key per integration. The sender computes a signature over a stable payload. You recompute and compare with a constant-time check.
- Sign the raw body bytes, not a re-serialized JSON object.
- Include a timestamp in the signed material and reject skew beyond a few minutes.
- Include an event id or delivery id so you can detect replays.
- Bind the signature to the path or tenant id when one secret covers many customers.
- Rotate secrets with an overlap window; accept both keys briefly, then drop the old one.
Reject requests with a missing signature, a bad signature, or a stale timestamp before you parse business fields. Return a generic 401 or 403. Do not echo why the check failed in a way that helps an attacker tune the forge.
Tie the callback to the original turn
When you start a tool call, store a server-side job record: user id, session id, tool name, idempotency key, and expected callback window. The webhook must present that job id. After signature checks, load the job and confirm the actor still matches.
Never trust a user id or account id inside the webhook body alone. The body can claim anything. Your job table is the source of truth.
- Mark the job complete once, using the idempotency key.
- Ignore duplicate deliveries after success.
- Do not feed unsigned or failed callbacks into the model context.
- For writes, keep the same confirm rules you use for sync tools.
Common mistakes
- Verifying a header against a pretty-printed body while the sender signed the raw bytes.
- Sharing one webhook secret across all tenants with no path or id binding.
- Accepting callbacks forever with no expiry on the job.
- Logging the full secret or the full signed payload in plaintext.
- Letting the model invent the callback URL; the URL must be yours and fixed per environment.
Tests and rollout
Unit-test good signatures, bad signatures, replayed event ids, and expired timestamps. Integration-test a forged body that would otherwise look like a successful tool result. The model must never see that forge.
Ship behind a flag. Start with read-only tool callbacks. Add write callbacks only after confirm and job binding are in place. Alert on signature failures by tenant; a sudden spike can mean a misconfigured client or an attack.
Signed webhooks keep async AI tools honest. Verify the signature. Bind the job. Only then let the result enter your app or the next model turn.
When you buy or sell an app that relies on AI tool callbacks, ask how webhooks are signed, how secrets are rotated, and whether unsigned deliveries can reach the model. Missing verification is a security debt. Price the work to fix it into the deal, or walk.
Ship the verifier with the first AI callback, not after the first strange POST lands.