Webhook Replay Attack Prevention: Best Practices
Learn webhook replay attack prevention best practices to stop duplicate events, protect your endpoints, and keep webhook processing secure.
WebhookGuide
May 5, 2026
Introduction
A webhook replay attack happens when an attacker captures a legitimate Webhook request and sends it again to trigger the same action twice. That can mean duplicate payment events, repeated account updates, or extra CI/CD notifications that create noise and confuse incident response.
Replay attacks matter because a consumer endpoint often accepts public inbound requests and processes them asynchronously. If your system trusts a repeated delivery without checking whether it has already seen it, the attacker can force duplicate side effects even when the payload itself is valid.
Webhook replay attack prevention is one layer of defense, not a replacement for signature verification, HTTPS, TLS, or Idempotent processing. You still need to verify the sender, protect the transport, and make your handlers safe to run more than once. For broader context, see webhook security best practices, best webhook security practices, webhook verification best practices, and secure webhooks best practices.
The practical defenses are straightforward: verify the signature, reject stale timestamps, check for a unique delivery ID, and deduplicate on the server side. Using GitHub webhooks as a concrete example, the next sections also show what to log when a replay is detected so you can investigate without creating more noise.
What is a webhook replay attack?
A replay attack uses a previously valid webhook request, not a forged one. An attacker captures a real event, such as a payment_succeeded or order_shipped notification, then resends it later so the consumer repeats the action.
This differs from Spoofing, where the attacker invents a fake sender, and Payload tampering, where the attacker changes the body in transit. A replay can still pass Signature verification or a Message authentication code check because the original request was authentic when first sent.
It also differs from normal Retry behavior: providers resend failed deliveries to ensure reliability, while a malicious replay is sent after a valid delivery already succeeded. For replay prevention and validation details, compare webhook validation techniques with webhook verification best practices.
Example: if a Stripe payment_succeeded webhook is replayed, your system might bill twice or fulfill the same order twice.
Why replay attacks are a risk
A replayed webhook can trigger real business damage: duplicate charges, repeated subscription changes, duplicate account provisioning, or unauthorized access changes. Even when signature verification uses HMAC or HMAC-SHA256, it only proves the payload came from the sender and wasn’t altered; it does not prove freshness, so the same signed request can be resent within its validity window.
Public consumer endpoint exposure, asynchronous queues, and distributed systems make replay detection harder because delayed or retried delivery is normal. If your handler lacks an Idempotency key, the same event can create duplicate downstream work, flood logs, and even contribute to denial of service by forcing repeated provisioning, billing, or notification jobs.
How replay prevention works
Webhook replay attack prevention uses a layered model: authenticate the sender with validation techniques, verify freshness, then reject previously seen deliveries. Providers may expose a Nonce, Unique event ID, Delivery ID, or Event ID; store that value server-side and compare each inbound request against your history to block duplicates.
Timestamp validation adds a second check by rejecting payloads outside an Expiration window, which limits the value of a captured request after the clock has moved on. The exact design depends on the provider’s webhook format, Retry behavior, and which headers or event metadata they actually send, so review the webhook implementation checklist before you choose a strategy.
Replay prevention reduces risk; Idempotent processing limits damage if a duplicate still gets through.
Does signature verification stop replay attacks?
No. Signature verification proves authenticity and integrity, but not freshness. A valid signature can be replayed if the attacker reuses the exact same request body and headers within the acceptance window.
That is why signature verification should be paired with timestamp checks and delivery deduplication. In practice, the Webhook secret is used to generate an HMAC or HMAC-SHA256 Message authentication code, and the consumer endpoint verifies that code before processing. But the signature alone does not tell you whether the request is new.
What is the difference between a replay attack and a duplicate webhook retry?
A replay attack is malicious or unauthorized reuse of a previously valid request. A duplicate webhook retry is usually a legitimate resend from the provider after a timeout, network failure, or non-2xx response.
The safest way to handle both is the same: verify the signature, check freshness, and make processing idempotent. If the provider retries the same Delivery ID or Event ID, your system should recognize it as already processed and return success without repeating side effects.
How do unique delivery IDs help prevent replays?
A Unique event ID or Delivery ID gives you a stable key to detect whether a webhook has already been processed. When the same ID arrives again, you can reject it before any business logic runs.
For GitHub webhooks, the X-GitHub-Delivery header is the delivery identifier. Store that value as soon as the request passes signature verification, then use it to block duplicates. If the same delivery arrives again, reject it even if the body is unchanged.
The best storage pattern depends on your scale and durability needs:
- Redis works well for fast, short-lived deduplication.
- A Database unique constraint works well when you need durable replay tracking.
- A dedicated table keyed by delivery ID or event ID is often the simplest option for auditability.
Use an atomic insert or SETNX-style operation so two concurrent requests cannot both win.
Should webhook handlers be idempotent?
Yes. Idempotent processing is one of the most important protections against replay attacks, retries, and race conditions in distributed systems.
A handler is idempotent when running it twice produces the same final state as running it once. For example, an order-creation webhook should check whether the order already exists before inserting a new record. A subscription update should compare the current state before applying the change again.
Idempotency is not a substitute for replay prevention, but it is the safety net that limits damage if a duplicate request slips through.
How long should webhook timestamps be considered valid?
There is no universal value, because the right Expiration window depends on the provider, the business risk, and your tolerance for Clock skew. A short window reduces replay exposure, but it can also reject legitimate requests if the sender and receiver clocks differ too much.
A practical approach is to accept timestamps only within the provider’s documented window and to compare them against server time in UTC. If the provider does not document a window, choose a conservative policy, monitor false rejections, and adjust only after testing.
Can payload hashes be used to detect replay attacks?
Payload hashing can help detect repeated bodies, but it should not be your primary replay defense. Two different events can legitimately share the same payload, and some providers may send identical content for separate state transitions.
A payload hash is best used as a secondary signal alongside delivery IDs, event IDs, and timestamp validation. If you use it, hash the canonical payload format exactly as the provider specifies, or the comparison may be unreliable.
Implementation patterns
Most teams combine three controls for webhook replay attack prevention: verify the signature, apply timestamp validation, and reject repeats with a stored delivery ID or event ID. Use Redis for fast lookups when traffic is high, or a Database unique constraint when you want persistence and simple duplicate rejection. For example, Stripe-style event IDs or GitHub delivery IDs can be written with an atomic insert so the first request wins and later replays fail cleanly.
Atomic writes matter in distributed systems and multi-region deployments because two regions can receive the same webhook at once. A unique index, SETNX in Redis, or a single transaction prevents race conditions better than “check then insert.” Use an expiration window that matches the provider’s signed timestamp policy, then reject stale deliveries outside that window. For billing or provisioning, add an idempotency key and idempotent processing so repeated valid requests do not repeat side effects. See the webhook implementation checklist and webhook best practices for developers for deployment patterns.
Best practices
Build webhook replay attack prevention as defense in depth: verify the signature, enforce HTTPS/TLS, reject stale timestamps, and store delivery IDs or event IDs to block repeats. Make critical handlers idempotent so payment_succeeded or subscription.updated events only apply once, even if the provider retries. A Stripe webhook that creates an order should check whether that order already exists before writing again.
Use structured logging for every rejected request: log the delivery ID, event ID, timestamp, signature result, source IP if available, and rejection reason. Feed those logs into monitoring and alerting for repeated IDs, signature failures, timestamp violations, and retry spikes. Protect each webhook secret in a secret manager, apply secret rotation on a regular cadence, and limit access with least privilege. Add rate limiting to slow noisy replay attempts and test your defenses in development, then retest after provider changes. For broader hardening, see webhook security best practices, secure webhooks best practices, and webhook best practices.
Common pitfalls
Signature verification alone is not webhook replay attack prevention. An attacker who captures a valid request can resend it before secret rotation or before your freshness window expires, and the HMAC still matches. Always pair X-Hub-Signature or X-Hub-Signature-256 checks with freshness rules and delivery deduplication.
Timestamp bugs also weaken defenses. Clock skew, local-time comparisons, or accepting stale requests indefinitely can turn a short replay window into no window at all. Use UTC, compare against server time, and reject requests outside a tight, documented range.
Avoid payload-only duplicate detection. Payload hashing can collapse distinct events that share the same body, especially when providers retry or emit similar updates. In webhook security best practices, the safer pattern is to key off provider delivery IDs, not content alone.
Distributed systems add race conditions. If one region evicts an ID from cache or writes it non-atomically, another region may accept the same delivery again. Use atomic inserts, shared storage, or a unique constraint, and account for retry behavior so legitimate retries are rejected only after the first successful processing.
For GitHub webhooks, verify the signature, then read X-GitHub-Delivery and store that ID before processing. If the same delivery arrives again, reject it even if the body is unchanged. See webhook validation techniques and webhook verification best practices for implementation details.
What should you log when a webhook replay is detected?
Log enough detail to investigate the event without exposing secrets. At minimum, record:
- delivery ID or event ID
- timestamp received
- signature verification result
- replay reason, such as duplicate ID or stale timestamp
Use structured logging so these fields are searchable. If the replay appears to be part of a broader attack, send the event to monitoring and alerting and preserve the raw request only if your security policy allows it.
What other webhook security controls should be used with replay prevention?
Replay prevention works best alongside broader API security controls:
- HTTPS/TLS to protect data in transit
- Webhook secret protection and Secret rotation
- HMAC-SHA256 or another strong Message authentication code
- Rate limiting to reduce abuse and noise
- Monitoring and alerting for repeated failures or duplicate IDs
- Structured logging for auditability
- OWASP-aligned API security practices
These controls help reduce spoofing, payload tampering, and denial of service, but they do not replace freshness checks or deduplication.
Webhook security checklist and conclusion
Use this webhook replay attack prevention checklist as a final pass before you ship:
- Verify HMAC signatures on every request. Reject anything that fails signature validation, even if the payload looks familiar.
- Validate timestamps and enforce an expiration window. If the request falls outside your allowed freshness window, treat it as stale and drop it.
- Store delivery IDs or event IDs. Use Redis for fast deduplication or a Database unique constraint for durable enforcement, and make the insert or mark-as-processed step atomic so two concurrent deliveries cannot both succeed.
- Make critical handlers idempotent. A payment, subscription, or provisioning handler should safely handle retries without repeating side effects. Use an Idempotency key when your workflow already supports one.
- Log rejected deliveries with structured logging. Record the reason for rejection, the delivery ID, and the timestamp. Feed those events into Monitoring and alerting so spikes in replay-like activity trigger an investigation.
- Enforce HTTPS/TLS and rotate secrets. Replay prevention depends on protecting requests in transit and limiting the lifetime of any compromised signing secret.
- Apply rate limiting. It will not stop a valid replay by itself, but it reduces abuse and buys time when an endpoint is under pressure.
The strongest webhook security setups combine authenticity checks, freshness checks, and deduplication with idempotent processing. That is the core of webhook replay attack prevention. Broader API security controls still matter: HTTPS, TLS, Secret rotation, and Rate limiting help reduce spoofing, tampering, and denial of service, which aligns with OWASP guidance and the broader webhook security best practices, best webhook security practices, webhook implementation checklist, and webhook best practices.
Webhook Delivery Failures: Causes, Fixes, and Prevention
Learn the causes of webhook delivery failures, how to fix them, and how to prevent missed events, duplicates, and downtime.
Webhook Error Handling Strategies: Reliable Delivery Guide
Learn webhook error handling strategies to validate, retry, dedupe, and recover from failures—build reliable delivery and protect every event.