HMAC-signed events

Webhooks

Push critical findings into your incident response, your ticketing, your Slack — the moment they're detected. No polling.

Event types

  • finding.createdA new finding has been detected.
  • finding.severity_changedA finding's severity was reclassified — usually after additional evidence is correlated.
  • finding.resolvedA finding was marked fixed or accepted as a known risk.
  • audit.startedA 4D forensic pass has begun.
  • audit.completedA 4D pass finished, with a summary payload of new and resolved findings.
  • resource.addedA new cloud resource entered the inventory.
  • policy.violatedA custom policy you defined was triggered.
POST /your-endpoint HTTP/1.1
Host: api.your-app.com
Content-Type: application/json
X-CloudSealed-Event: finding.created
X-CloudSealed-Event-Id: evt_01HZ8K3F2Q4XV6
X-CloudSealed-Timestamp: 1717693200
X-CloudSealed-Signature: sha256=8b9c4a...

{
  "event_id": "evt_01HZ8K3F2Q4XV6",
  "type": "finding.created",
  "created_at": "2026-06-06T14:22:11Z",
  "data": {
    "finding": {
      "id": "fnd_8f3a2c1b",
      "severity": "critical",
      "dimension": "security",
      "resource_id": "res_aws_s3_42",
      "title": "Public S3 bucket exposing customer PII"
    }
  }
}

Delivery semantics

  • POST with JSON body, content-type application/json.
  • Retries: up to 8 attempts over 24 hours with exponential backoff.
  • Timeout: 10 seconds. Return 2xx fast and queue the work asynchronously.
  • Idempotency: every delivery carries a stable event_id header. Dedupe on it.

Signature verification

Every payload is signed with HMAC-SHA256 over the raw request body using your endpoint secret. The signature ships in the X-CloudSealed-Signature header alongside an X-CloudSealed-Timestamp. Reject any request whose signature doesn't match — never trust the payload otherwise. Reject timestamps older than five minutes to prevent replay.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyCloudSealed(req, secret) {
  const signature = req.headers["x-cloudsealed-signature"];
  const timestamp = req.headers["x-cloudsealed-timestamp"];

  // Reject replays older than 5 minutes
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected =
    "sha256=" +
    createHmac("sha256", secret)
      .update(timestamp + "." + req.rawBody)
      .digest("hex");

  const a = Buffer.from(signature);
  const b = Buffer.from(expected);
  return a.length === b.length && timingSafeEqual(a, b);
}