fix(audit): webhook cluster — M21 (test-send isActive), M22 (cross-tenant dead-letter), L28 (ipv6 SSRF), L29 (rebind doc), L30 (replay event-time)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -309,10 +309,20 @@ export async function redeliverWebhookDelivery(
|
||||
.limit(1);
|
||||
if (!source) throw new NotFoundError('Delivery');
|
||||
|
||||
// L30: redeliver intentionally RE-SIGNS the original captured payload with a
|
||||
// FRESH signature + fresh `X-Webhook-Timestamp` at dispatch time (see worker
|
||||
// `finalPayload`). A receiver that judges freshness solely from the transport
|
||||
// timestamp / delivery id would therefore accept arbitrarily-old event data
|
||||
// as if it were new. This is by design (replaying a missed delivery), but the
|
||||
// business-level event age must travel inside `data` so receivers can apply
|
||||
// an event-time freshness check independent of the transport envelope. We
|
||||
// surface the ORIGINAL delivery's `createdAt` as `original_event_at` (and keep
|
||||
// the existing `retried_from` / `retried_at` replay markers).
|
||||
const replayPayload = {
|
||||
...(source.payload as Record<string, unknown>),
|
||||
retried_from: deliveryId,
|
||||
retried_at: new Date().toISOString(),
|
||||
original_event_at: source.createdAt?.toISOString() ?? null,
|
||||
};
|
||||
|
||||
const [next] = await db
|
||||
@@ -363,6 +373,14 @@ export async function sendTestWebhook(portId: string, webhookId: string, eventTy
|
||||
throw new NotFoundError('Webhook');
|
||||
}
|
||||
|
||||
// M21: mirror redeliverWebhookDelivery — refuse to fire a live signed POST
|
||||
// for a webhook an admin has explicitly disabled (e.g. because its endpoint
|
||||
// was flagged). Without this, the test button is a convenient operator-
|
||||
// controlled trigger for an otherwise-inert webhook.
|
||||
if (!webhook.isActive) {
|
||||
throw new NotFoundError('Webhook is inactive');
|
||||
}
|
||||
|
||||
// Create a pending delivery record
|
||||
const [delivery] = await db
|
||||
.insert(webhookDeliveries)
|
||||
|
||||
Reference in New Issue
Block a user