Secure Webhook Subscriptions for Rocky

Webhook subscriptions let external services trigger Hermes as soon as an event happens. They remove polling delay, but they also create a public-facing input boundary that deserves careful design.

Official documentation: https://hermes-agent.nousresearch.com/docs/user-guide/messaging/webhooks

Build the route around one event

A route should identify the accepted event type, signature secret, prompt template, skills, and delivery target. Prefer a small template that selects only the fields the workflow needs. Dumping an entire upstream payload into an agent prompt increases noise and enlarges the prompt-injection surface.

For notification-only events, direct delivery can avoid an agent run entirely. Use reasoning only when the workflow genuinely needs classification, synthesis, or a decision.

Security checklist

  • [ ] Use a unique HMAC secret for each meaningful route.
  • [ ] Keep unauthenticated test mode bound to loopback only.
  • [ ] Restrict accepted event types.
  • [ ] Bound body size and request rate.
  • [ ] Preserve a stable delivery ID or request ID for retry deduplication.
  • [ ] Treat titles, descriptions, comments, and commit messages as untrusted text.
  • [ ] Give the triggered agent the smallest practical toolset.
  • [ ] Keep destructive, payment, credential, and public-post actions behind approval.

Authenticated does not mean trusted

A valid signature proves which service sent the request; it does not prove that every business field is safe. A signed GitHub event may still contain an issue title written by a stranger. The durable defense is capability control: limit tools, scope credentials, validate structured fields in trusted code, and require approval for consequential side effects.

Delivery and retry design

Hermes can route results to logs or configured messaging destinations. Test the real destination, not only the webhook HTTP status. Upstream services retry, so use their delivery identifier when available. Distinct logical events need distinct request IDs; reusing one identifier can make a legitimate second event look like a duplicate.

Pitfalls

  • Reusing one global secret across unrelated integrations.
  • Accepting every event and filtering only inside the model prompt.
  • Exposing a loopback test route on a public interface.
  • Giving a public-input agent terminal and file tools just to format a message.
  • Reporting “delivered” from a 200 response without checking the target channel.
  • Ignoring duplicate retries or rate-limit behavior.

Verification steps

  • Check the local webhook health endpoint.
  • Send a correctly signed synthetic event with fake data.
  • Confirm an invalid signature is rejected.
  • Repeat the same delivery ID and confirm it is not processed twice.
  • Exceed the test rate limit and confirm a controlled response.
  • Verify the final message or agent output in the configured destination.
  • Inspect gateway logs for secrets, payload over-sharing, and unexpected tool calls.