Research & Analysis · Software engineering · 17 min read
Can You Trust a Signed Webhook to Update a Business Record?
Sources checked against the cited passages; awaiting my final read before this is indexed.
A valid webhook signature is necessary when the integration relies on that signature, but it is not sufficient permission to change a business record. You also need to establish which sender and tenant the event belongs to, which parts of the request were protected, whether the event is a duplicate or stale observation, and whether the proposed state transition remains valid. Then you need a recovery path for events that never arrive.
I would review the integration as a chain of decisions, from external notification to committed business effect. “The endpoint checks signatures” answers one part of that chain. It doesn't establish that a delayed cancellation won't reverse a later reinstatement, that an event from one customer won't update another customer's record, or that a retry won't create a second downstream action.
This paper develops an acceptance method from twelve original standards, technical references and systems-design research sources. It includes a fictional subscription example, not a customer incident or an experiment. The method is a proposed architecture review, not a universal webhook implementation or evidence that any named service is insecure.
Start with the business effect and its owner
Before inspecting the endpoint, identify what an accepted event can cause. Updating a display cache, granting access, changing an entitlement and initiating an external transaction have different consequences. A notification that is adequate for refreshing a dashboard may be inadequate authority for an irreversible operation. The architecture should make that distinction before a developer chooses the success response code.
NIST SP 800-47 Rev. 1 treats protection of exchanged information before, during and after an exchange, including the agreements needed to manage it. It deliberately does not prescribe one connection technology (Dempsey et al., 2021). I would use that scope to establish responsibilities: who owns the source truth, who approves the receiving system's use, who maintains credentials, and who resolves disagreement between the two systems.
Define the meaning of the event. Is it an instruction to perform an action, a snapshot of state at an earlier time, or a hint to retrieve current state? Those meanings are not interchangeable. If the provider documents a historical snapshot, interpreting it as the latest state creates a correctness problem even when its origin and contents are authentic. If it is merely a notification, the receiving application may need a separate authorized read before deciding what to do.
The review output should name the permitted local transitions. For example, a cancellation notice might make a record eligible for reevaluation without directly revoking every associated entitlement. A business owner must decide which source facts justify the change and which exceptions require intervention. The integration team's job is to enforce that declared rule, not infer business authority from the presence of a trusted provider's logo.
Know exactly what the signature establishes
A signature scheme has a coverage contract. RFC 9421 defines signatures or message authentication codes over selected HTTP components and requires applications to specify additional verification requirements. Its security discussion warns that unsigned components can change processing without invalidating the signature (Backman et al., 2024, §§3.2.1, 7.2.1). A verification library returning true is useful only when the protected components include what your application relies on.
Write down the authenticated bytes and context for the actual provider. Does protection include the body, destination, timestamp, event identifier or routing headers? Which values remain ordinary untrusted input? Do not assume every webhook uses RFC 9421; many use provider-specific schemes. Apply the documented scheme and separately examine whether its guarantees support the local decision.
GitHub, for example, documents an HMAC-SHA256 signature derived from the configured secret and payload, together with constant-time comparison guidance and a published validation example (GitHub, n.d.). That establishes a particular body-verification procedure. It doesn't automatically authenticate every additional header your routing code might consume. I would avoid selecting a tenant solely from a header unless the integration's trust model independently protects that selection.
Also distinguish possession of a shared signing secret from independent proof about one organization. If several endpoints or tenants share a secret, a valid MAC establishes less isolation than separate trust contexts would provide. That is an architectural implication, not a claim that the provider requires shared secrets. Document which components can generate valid requests and what compromise of each would allow; don't quietly assume the receiver's secret store is outside the threat model.
Key changes need a separate acceptance case. During an authorized rotation, the receiver may temporarily recognize more than one configured key. Define which integration each key belongs to, how long overlap is permitted and how the system records which key validated a delivery. A request-supplied key identifier can select among trusted configured candidates; it should not authorize fetching an arbitrary replacement key from a location supplied by the request itself. This is a proposed verification boundary, not a claim about any provider's rotation API.
Stopping the integration also needs a defined effect on deliveries already accepted. Removing an ingress key can stop new verification without removing events already present in a worker queue. The processor should consult the integration's current processing policy where revocation is intended to stop pending changes. Alternatively, a business owner may explicitly authorize a bounded drain of previously accepted work. Preserve that choice in the operating contract and test it; don't infer it from a disabled webhook toggle.
Preserve the protected representation through parsing
Verification must apply to the representation the signer protected. A proxy, middleware layer or parser can alter whitespace, encoding or request contents before the verifier sees them. I would trace where raw bytes become a parsed object, which transformations occur first, and which representation the application actually uses for its decision. A successful check on one representation should not authorize unrelated values extracted from another.
RFC 9530 distinguishes content digests from representation digests and states that digest fields alone do not provide general protection against malicious modification. An attacker able to replace data may replace an unprotected digest too; combining integrity fields with signatures or TLS introduces further context requirements (Polli & Pardue, 2024, §§2–3, 6.1–6.3). A digest is not a substitute for authenticating the sender or protecting the metadata that determines interpretation.
After verifying the supported signature, validate the event schema and reject ambiguous or unsupported forms. Decide how duplicate field names, unexpected types, oversized bodies and unknown event versions are handled. These are proposed acceptance cases. A parser accepting a payload doesn't establish that its fields have the business meaning the handler expects, and a fallback that silently ignores an important field can change the authorized operation.
Keep the trust transition explicit inside the application. The verified envelope, parsed event and business command are different objects with different guarantees. If a later transformation adds a tenant identifier, defaults a status or resolves an object reference, record the trusted basis for that value. Otherwise a clean signature check at ingress can conceal a weak decision made several functions later.
Bind the event to the correct integration and tenant
A provider can legitimately send events about many accounts. The receiver needs a protected association between the configured integration, external account, local tenant and eligible business objects. A globally unique-looking object identifier is not enough if the handler never verifies that the object belongs to this integration. Authentication of the sender and authorization of the local update are separate obligations.
CloudEvents 1.0.2 specifies uniqueness using the combination of source and id; consumers may regard repeated events with identical values as duplicates. The source attribute identifies event context according to producer-defined semantics (CloudEvents Authors, n.d.). This is useful for designing event identity, but the format does not prove that a claimed source owns a local tenant. A structured source string must still be interpreted within an authenticated producer relationship.
I would derive the local tenant from a protected subscription or integration record, then check that the event's external account and object match that record. If the payload includes a local tenant ID for convenience, treat it as a value to compare rather than permission to select arbitrary records. The update should retain that tenant condition through the data operation, not check it once and then write using only an unscoped object ID.
Test this boundary with two authorized test integrations. Deliver a correctly signed event under one context while naming an object belonging to the other. The required result is rejection or quarantine without cross-tenant mutation. This is stronger evidence than sending an invalid signature and observing an error: the request is authentic at one boundary but unauthorized at the next, which is precisely the distinction the design must preserve.
Separate replay freshness from duplicate business effects
A copied valid request may be replayed, while a legitimate provider may also redeliver an event. A freshness window and a processed-event record address different parts of that problem. The first constrains how long a captured delivery remains acceptable under the signature policy. The second records whether the application has already dealt with a particular event or effect.
Stripe documents signed timestamps for replay mitigation, duplicate event delivery and the absence of a guaranteed delivery order. It also notes that separate event objects can sometimes describe duplicate activity (Stripe, n.d., “Preventing replay attacks,” “Handle duplicate events,” and “Event ordering”). These are provider-specific semantics. I would use them to challenge a design that assumes one valid signed HTTP request equals one new business action, not generalize every detail to other providers.
Define the event-identity namespace and the business-effect identity separately. One identifier may describe an individual notification; another may describe the local operation that should happen only once. Two different notifications can justify the same desired-state update, while repeated notifications about an evolving object can represent genuinely different changes. Deduplicating forever on the object ID would suppress legitimate later work.
The retention policy also matters. Deleting deduplication records can make an old event appear new again. Keeping every payload forever can create unnecessary sensitive-data exposure. I would retain the minimum identity, decision and outcome evidence needed for the documented retry and reconciliation horizon, with an explicit treatment of older deliveries. A time limit is a design assumption to defend, not a number that becomes safe because it fits a convenient cache setting.
Make acknowledgment, receipt and effect different states
An HTTP success response tells the sender something about request handling, but your application must define whether it means verified receipt, durable acceptance or completed processing. RFC 9110 describes 202 Accepted as noncommittal: processing has not completed and may ultimately fail (Fielding et al., 2022, §15.3.3). The precise provider contract still determines which responses stop retries; HTTP semantics alone do not define your delivery agreement.
For an asynchronous design, I would prefer a clear handoff: validate the request, durably record enough trusted context to process it, and acknowledge according to the provider's documented requirements. The worker then records the business decision and its result. If the service acknowledges before the event survives a process crash, a later recovery may have nothing to replay even though the sender believes delivery succeeded.
There is another failure interval after the business update but before the processed-event marker is committed. A retry can repeat the effect unless the design couples those records or otherwise makes the operation safe to repeat. A database transaction may help for local state, but it doesn't automatically include an external email, entitlement service or other remote effect. Identify each boundary rather than promising atomicity across components that don't share it.
Google Cloud's Pub/Sub documentation illustrates how carefully delivery claims need scoping: exactly-once delivery is supported for pull subscriptions within its documented conditions, not push or export subscriptions, and publish-side duplicates remain a separate consideration (Google Cloud, n.d.). Even when transport duplicate suppression is available, the review still needs to establish the application's effect semantics. A queue feature is not an all-purpose guarantee that the business action occurs exactly once.
Handle ordering according to source semantics
A signed event can accurately describe yesterday. If it arrives after a later event, blindly overwriting local state may reverse a valid transition. I would ask whether the provider exposes a monotonic object revision, an ordered stream, a durable change cursor, or only a timestamp and event ID. Each supports different conclusions; none should be invented by the receiving application.
A timestamp may describe event creation rather than a total ordering of all changes. Identical timestamps and clock differences can make a simple “newer wins” rule ambiguous. Use a revision comparison only when the producer documents what advances the revision and the domain in which it is ordered. Comparing versions from different objects or accounts can produce a plausible numerical result with no meaningful ordering guarantee.
For an integration maintaining current state, a notification can instead trigger an authorized refresh from the source system. That can avoid applying an old snapshot as if it were current, but it changes the meaning of processing: several events may collapse into one current-state observation. If the business needs every intermediate transition for an audit or a financial operation, a current-state fetch is not a substitute for a complete event history.
I would write the choice explicitly: preserve historical transitions, converge to current state, or combine both with distinct records. Then test delayed, reversed and missing events against that contract. The right outcome is not always “ignore the older event.” An older event may contain a historical fact that must be retained even when it must not overwrite today's entitlement.
Treat missing notifications as a normal recovery requirement
A quiet endpoint can mean no changes, a broken subscription, expired authorization or a delivery failure. The absence of incoming events does not establish that the local replica is current. The review should identify how the integration detects a gap, which source can repair it and when the business must stop relying on potentially stale local data.
Microsoft Graph lifecycle guidance describes missed notifications and instructs applications to resynchronize affected resource data, for example through delta query. It also documents resource-specific support for lifecycle notification types (Microsoft, 2026). I would use that as a concrete example of a provider acknowledging the need for recovery beyond normal event delivery. It is not evidence that every Graph resource supports the same notification or recovery mechanism.
Delta-query semantics deserve their own review. Microsoft documents opaque state tokens, continuation links, repeated or unordered items during synchronization and cases where a 410 response requires a full synchronization restart (Microsoft, 2025). A receiver cannot safely invent cursor contents, advance past unprocessed pages or assume that restarting always means clearing and rebuilding every local business record. The merge procedure must respect the resource's documented contract.
Separate reconciliation of source state from replay of business side effects. Discovering during resynchronization that an account is active may justify correcting a local entitlement. It doesn't necessarily justify resending every welcome message that the original activation once produced. I would classify which effects are state-derived and repeatable, which are historical one-time actions, and which require manual resolution when their earlier outcome is unknown.
Don't let a reference in the event choose the next trust boundary
Fetching current state introduces an outbound request. A payload may contain a URL or object reference, but an authentic event is not blanket permission for the receiver to contact any address it names. The source system might include user-controlled fields, a compromised upstream account might influence the event, or a redirect might move the request outside the intended provider boundary.
OWASP's SSRF prevention guidance distinguishes requests to known trusted applications from requests to arbitrary destinations, recommends allowlisting where feasible and discusses redirect and network-layer controls (OWASP Foundation, n.d.). For this integration, I would prefer resolving an object identifier through the provider's known API base and the credential belonging to the configured tenant. That is narrower than following a free-form URL while carrying a powerful service credential.
The fetching code also needs a defined authorization context. If it uses an organization-wide credential because tenant-scoped credentials are inconvenient, a mistake in reference resolution can expose a much larger data set. Limit fields and resources to what the synchronization task needs, and keep the response subject to schema and ownership checks. Receiving a successful API response does not establish that it was the intended object's response.
Include denial tests for an unexpected destination, a redirect outside the allowed boundary and an object from another integration context. Run them in a controlled harness without probing real internal networks. The objective is to prove that an event cannot enlarge the receiver's outbound authority, not to turn an architecture review into an uncontrolled network assessment.
A fictional subscription event that should not revoke access
Suppose a fictional service sends subscription snapshots to an internal entitlement system. Tenant Cedar's subscription object S4 has documented revisions 18 and 19. Revision 18 says cancelled; revision 19 says active after reinstatement. The local system already holds revision 19. This invented provider contract supplies per-object monotonic revisions, and the local purpose is convergence to current entitlement state rather than recreation of every historical side effect.
The following outcomes follow from those stipulated facts. They are not results of a live integration test or claims about a named provider.
| Incoming event | Required decision in this fictional design | Reason |
|---|---|---|
| Validly signed S4 cancellation at revision 18 | Preserve active revision 19; retain relevant history | Authentic older state must not replace the current state |
| Duplicate notification for revision 19 | No second activation side effect | Delivery repetition doesn't create a new business transition |
| Valid event associated with another tenant's integration | Reject the cross-tenant update | Sender authenticity doesn't confer local object authority |
| Lifecycle notice indicating missed events | Reconcile authorized source state | The event stream no longer establishes local completeness |
| Source refresh fails while the local status may be stale | Mark freshness unresolved and apply the agreed business policy | Silence and network failure don't prove active or cancelled state |
The last row is where architecture becomes a business decision. Automatically retaining access can be inappropriate for a sensitive entitlement; automatically revoking it can interrupt a critical service. The responsible owner must choose the degraded-state rule, including escalation and any bounded exception. The engineering record should show the uncertainty rather than manufacturing a confident status to keep the interface tidy.
If this fictional provider offered no ordered revision, the first row would need a different decision procedure. The receiver might retrieve current state, use a supported change feed or defer the consequential update. It could not simply rename an event timestamp “revision” and keep the same proof. The assurance claim depends on the source contract, which is why that contract belongs beside the diagram.
Prove the complete path without overclaiming the result
Saltzer, Reed and Clark's end-to-end argument explains why functions such as duplicate suppression and delivery assurance may require application-level knowledge even when lower layers provide useful support (Saltzer et al., 1984). I would apply that reasoning to the actual business effect. Signature verification, queue delivery and database writes are valuable components, but the system's correctness depends on how their guarantees compose.
Start with a traceable acceptance case: one authorized event, the expected local transition and an independent observation of the resulting state. Then vary signature validity, protected-field coverage, tenant context, event identity, ordering, delivery repetition, worker failure and reconciliation state. Test the original event path and the repair path; a secure normal handler does not compensate for an overprivileged bulk resynchronization job.
Record what each failure proves. An invalid signature rejected before parsing supports an ingress claim. A correctly signed wrong-tenant event rejected at the update supports an authorization claim. A repeated event with no additional effect supports a duplicate-processing claim under the tested state. None alone establishes the other properties, and a clean run doesn't prove every interleaving has been examined.
Keep evidence proportionate. Retain integration identity, event identity, relevant source revision, verification outcome, decision reason, processing state and authoritative effect references, with secrets and unnecessary personal data removed. The record should let another engineer distinguish “received,” “ignored as stale,” “reconciled” and “applied.” An attractive dashboard count of accepted requests cannot make those distinctions for them.
Decide whether the remaining uncertainty is acceptable
This level of review can be excessive for a disposable notification that only refreshes a noncritical display. I would scale the evidence to the consequence and state the smaller claim honestly. A simple integration can be appropriate when duplicate or delayed updates have little effect and a reliable refresh repairs them. The problem is importing that design unchanged into access control or another consequential business process.
There is also a cost to repeated source lookups and broad reconciliation. Rate limits, service availability and data volume can make fetching everything on every event impractical. Those constraints call for an explicit synchronization design and recovery budget. They don't turn an unordered notification into an ordered command or make missing events impossible.
For supplier assurance, use the supplier-evidence review; it addresses the organization and product relationship. For data leaving your environment, use the cloud-egress boundary analysis. This paper addresses the inbound transition from authenticated notification to correct local effect. The sources support its component reasoning; they do not validate your deployed integration or supply a universal recovery deadline.
If a critical integration is approved because “the webhook is signed,” request an integration trust-boundary review. Bring one sanitized event contract, the receiving workflow and the business record it can change. I can help identify which guarantees you actually have, which decisions remain unsupported and which controlled acceptance tests would resolve them.
References
- Backman, A., Richer, J., & Sporny, M. (2024, February). HTTP message signatures (RFC 9421). Internet Engineering Task Force. https://www.rfc-editor.org/rfc/rfc9421.html
- CloudEvents Authors. (n.d.). CloudEvents specification (Version 1.0.2). Retrieved October 29, 2026, from https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md
- Dempsey, K., Pillitteri, V. Y., & Regenscheid, A. (2021, July). Managing the security of information exchanges (NIST Special Publication 800-47, Rev. 1). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.SP.800-47r1
- Fielding, R., Nottingham, M., & Reschke, J. (Eds.). (2022, June). HTTP semantics (RFC 9110). Internet Engineering Task Force. https://www.rfc-editor.org/rfc/rfc9110.html
- GitHub. (n.d.). Validating webhook deliveries. Retrieved October 29, 2026, from https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries
- Google Cloud. (n.d.). Exactly-once delivery. Retrieved October 29, 2026, from https://docs.cloud.google.com/pubsub/docs/exactly-once-delivery
- Microsoft. (2025, April 30). Use delta query to track changes in Microsoft Graph data. Microsoft Learn. https://learn.microsoft.com/en-us/graph/delta-query-overview
- Microsoft. (2026, March 24). Reduce missing change notifications and removed subscriptions. Microsoft Learn. https://learn.microsoft.com/en-us/graph/change-notifications-lifecycle-events
- OWASP Foundation. (n.d.). Server side request forgery prevention cheat sheet. Retrieved October 29, 2026, from https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
- Polli, R., & Pardue, L. (2024, February). Digest fields (RFC 9530). Internet Engineering Task Force. https://www.rfc-editor.org/rfc/rfc9530.html
- Saltzer, J. H., Reed, D. P., & Clark, D. D. (1984). End-to-end arguments in system design. ACM Transactions on Computer Systems, 2(4), 277–288. https://web.mit.edu/saltzer/www/publications/endtoend/endtoend.pdf
- Stripe. (n.d.). Receive Stripe events in your webhook endpoint. Retrieved October 29, 2026, from https://docs.stripe.com/webhooks