Eventos firmados con HMAC
Webhooks
Empuja findings críticos a tu respuesta a incidentes, tu ticketing, tu Slack — en el momento en que se detectan. Sin polling.
Tipos de evento
finding.createdSe detectó un nuevo finding.finding.severity_changedSe reclasificó la severidad de un finding — usualmente tras correlacionar nueva evidencia.finding.resolvedUn finding fue marcado como corregido o aceptado como riesgo conocido.audit.startedUna pasada forense 4D arrancó.audit.completedUna pasada 4D terminó, con payload que resume findings nuevos y resueltos.resource.addedUn nuevo recurso de nube entró al inventario.policy.violatedSe disparó una política a medida que definiste.
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"
}
}
}Semántica de entrega
- —POST con body JSON, content-type application/json.
- —Reintentos: hasta 8 intentos en 24 horas con backoff exponencial.
- —Timeout: 10 segundos. Devuelve 2xx rápido y encola el trabajo de forma asíncrona.
- —Idempotencia: toda entrega trae un header event_id estable. Hazle dedupe.
Verificación de firma
Todo payload se firma con HMAC-SHA256 sobre el cuerpo crudo de la solicitud usando el secret de tu endpoint. La firma viaja en el header X-CloudSealed-Signature junto a un X-CloudSealed-Timestamp. Rechaza cualquier solicitud cuya firma no coincida — nunca confíes en el payload sin esto. Rechaza timestamps con más de cinco minutos para impedir 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);
}