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);
}