Webhooks are one of the most common integration points in modern software, and they are also one of the most commonly misconfigured. An unsigned webhook is little more than an unauthenticated HTTP endpoint that will trigger real actions in your system in response to any POST request, regardless of origin. Adding HMAC-based signatures and a timestamp replay window closes most of the practical attack surface at minimal complexity cost.
Why Unsigned Webhooks Are a Security Problem
When an external service calls your webhook endpoint, your system has to decide whether to act on the payload. Without a signature, the only thing you can verify is that someone sent a POST request to the right URL. That is not enough.
Consider a few concrete risks. First, spoofing: anyone who discovers or guesses your webhook URL can send fabricated events. If your system triggers a workflow, sends a notification, or updates records in response, an attacker can drive those actions at will. Second, replay attacks: even if you trust the original sender, a network attacker who captures a legitimate webhook delivery can re-send the same payload minutes or hours later, triggering the same side effects again. Third, man-in-the-middle modification: without an integrity check, an adversary on the network path between sender and receiver can alter the payload in transit. Your system never knows the data it received differs from what was sent.
These are not hypothetical. Webhooks routinely trigger financial transactions, privilege changes, data writes, and automation sequences. The stakes are high enough to warrant a proper verification layer.
How HMAC Signatures Work
HMAC (Hash-based Message Authentication Code) solves the integrity and authenticity problems by having both the sender and receiver share a secret key. When the sender constructs a webhook delivery, it computes a hash of the payload using the shared secret:
signature = HMAC-SHA256(secret, payload)
The signature is sent in an HTTP header alongside the request body. When your server receives the request, it independently computes the same HMAC using its own copy of the secret. If the two signatures match, you have two guarantees: the payload has not been modified in transit, and the sender possessed the secret key. An attacker who does not know the secret cannot produce a valid signature for any payload, real or fabricated.
The choice of HMAC-SHA256 is deliberate. HMAC is resistant to length-extension attacks that affect plain hash functions, and SHA-256 provides a collision resistance level that is more than sufficient for this use case. Equally important: the signature comparison on the receiver side should always use a constant-time equality function to avoid timing side-channels that could leak information about the expected value.
Adding Timestamp Verification to Stop Replays
HMAC signatures alone do not stop replay attacks. A valid signed request from five minutes ago is still cryptographically valid today. An attacker who captures a delivery in transit can re-submit it, and your signature check will pass.
The standard defense is to include a timestamp in the signed material and enforce a freshness window. The sender includes the current Unix timestamp in a dedicated header and signs a combined payload constructed as:
signed_material = "${timestamp}.${raw_body}"
The receiver checks two things: the HMAC over the combined string matches, and the timestamp falls within an acceptable window — typically two to five minutes on either side of the current server time. Deliveries with timestamps outside that window are rejected, even if the signature is otherwise valid.
This pattern is deliberately simple to implement and audit. It requires no shared state between receiver instances — just a clock comparison and a hash. Both sides need reasonable clock synchronisation (NTP is sufficient), and the window should account for the maximum expected delivery latency of the sending service.
The Shared Secret: Generation, Storage, and Rotation
The security of the entire scheme depends on the shared secret remaining secret. A few principles apply.
Generation: secrets should be produced by a cryptographically secure random number generator with at least 32 bytes (256 bits) of entropy. Do not derive secrets from predictable values such as record IDs, timestamps, or hashes of configuration data.
Delivery: the secret should be shown to the operator exactly once, at the moment it is created, and not stored in retrievable plaintext form. Rotating is the only recovery path if it is lost.
Rotation: secret rotation is a routine maintenance task, not only an emergency response. Rotate when team members with access to the secret leave, when you suspect exposure, or on a scheduled cadence. Good webhook tooling supports a brief overlap window — a period where both the old and new secrets are valid — so in-flight deliveries are not dropped during the transition.
Storage: secrets must never appear in logs, monitoring dashboards, error traces, or configuration files in plaintext. Store them encrypted at rest and restrict access to the processes that need to perform the HMAC computation.
Validating the Raw Body, Not the Parsed Object
One subtle but important implementation detail: HMAC must be computed over the raw request body bytes, not over any derived representation. JSON parsers may normalize whitespace, reorder keys, strip trailing zeros from numbers, or alter encoding in ways that change the serialized form without changing semantic content. If you parse the body first and then re-serialize to verify the signature, the result may differ byte-for-byte from what the sender originally signed.
Always buffer the raw body before parsing and compute the HMAC over the buffer. In practice this means configuring your HTTP framework to expose the raw body alongside the parsed object, or buffering it yourself before parsing. This is a common source of "signature always fails" bugs in new integrations.
Common Implementation Mistakes
Even teams that know to use HMAC often ship a weak implementation. A few patterns to watch for:
Comparing signatures with ==: string equality operators in most languages return early on the first differing character. An attacker who can probe your endpoint with crafted signatures and measure response latency can, in theory, infer information about the expected value one character at a time. Use a purpose-built constant-time comparison instead.
Treating a missing signature header as a pass: if the signature header is absent, the request should be rejected, not forwarded to your handler as "unverified." Some implementations treat a missing header as a permissive case, which defeats the scheme entirely.
Parsing the timestamp but not enforcing the window: a common oversight is to parse the timestamp header, confirm it is a valid number, but never actually compare it against the current time. The window check is as important as the HMAC check.
Using the webhook URL path as a security boundary: a long, random path is security through obscurity. It slows discovery but provides no cryptographic protection once the URL leaks — and URLs leak readily through logs, referrer headers, and monitoring tools.
Logging raw headers including the signature value: log pipelines are often less tightly controlled than application secrets. Avoid logging the signature header value, and redact it from any error trace that captures request headers.
Webhook Security in Practice
A complete webhook security implementation combines all the controls described above: HMAC-SHA256 signatures over the combined timestamp and raw body, constant-time comparison, a replay protection window rejecting stale timestamps, per-IP rate limiting on the public receiver, and a delivery audit trail that records accepted and rejected requests with their validation outcomes.
When an operator configures a webhook trigger for a workflow, the platform generates a cryptographically secure secret and presents it once. Secrets can be rotated on demand with an overlap window so in-flight deliveries are not dropped during the transition. Past deliveries can be replayed, supporting routine key hygiene and incident recovery. For more on how webhooks integrate with outbound event delivery and SIEM forwarding, see webhooks and SIEM forwarding. For how signed webhooks function as workflow triggers, see triggering workflows: scheduled, webhook, and event.
Common Questions
Does HMAC signing work if the webhook is called by a third-party service I do not control? It depends on whether that service supports configurable shared secrets and signature headers. Most serious webhook providers — payment processors, CI systems, identity platforms — do. For services that do not, your fallback options are IP allow-listing to restrict which source addresses can reach the endpoint, a signed relay that re-signs the request before forwarding it, or accepting reduced assurance and treating the endpoint as lower-trust. Check what the sending service supports before choosing an approach.
What should I do if a webhook secret is compromised? Rotate immediately. Generate a new secret, update the sender's configuration with the new value, and verify the sender has switched over before disabling the old one. Examine delivery logs for unexpected replays or anomalous payloads in the window between the suspected compromise and the rotation. After confirming the sender is using the new secret, revoke the old one and audit wherever it may have been stored or logged.
Is a long, random path in the webhook URL enough protection on its own? No. A secret path provides no cryptographic guarantee — it reduces exposure by making the endpoint harder to discover by scanning, but that protection evaporates the moment the URL appears in a log, a browser history, a network trace, or a misconfigured monitoring tool. HMAC signing provides a guarantee that holds even if the URL is fully public, because validity depends on the secret key rather than the URL's obscurity.
How does webhook signing relate to broader AI platform security? Webhook signing addresses integrity and authenticity at the integration boundary. It is one layer in a broader security model that also includes secrets management for AI agents to protect credentials in transit and at rest, and audit trails that hold up to ensure every delivery is durably recorded for compliance purposes. For how signed webhooks are used specifically as workflow triggers, see triggering workflows: scheduled, webhook, and event.