Webhooks
PromptShield envía notificaciones HTTP a tu URL cuando se bloquea un ataque o se detecta actividad sospechosa. Firmados con HMAC-SHA256 estilo Stripe.
Configuración
- Ve a dashboard → Webhooks y crea un endpoint.
- Selecciona los eventos a recibir.
- Guarda el
signing_secretque aparece una sola vez.
Eventos disponibles
attack.blocked— Mensaje bloqueado por L1, L1.5 o L2.attack.medium_risk— Mensaje sospechoso (no bloqueado).output.blocked— Respuesta del LLM bloqueada por L5.
Payload
{
"id": "evt_abc",
"type": "attack.blocked",
"created_at": "2025-05-02T19:00:00Z",
"project_id": "prj_xxx",
"data": {
"request_id": "req_xyz",
"message_hash": "sha256:...",
"risk_level": "high",
"category": "prompt_injection",
"reason": "pattern_match",
"layer_blocked": 1,
"session_id": "sess-1",
"user_id": "user-42"
}
}Verificar la firma (Node)
El header PromptShield-Signature tiene formato t=<unix>,v1=<hex>. Calcula HMAC-SHA256(secret, "${t}.${rawBody}") y compara con tiempo constante.
import crypto from 'node:crypto';
export function verify(rawBody: string, header: string, secret: string): boolean {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const t = parts.t as string;
const v1 = parts.v1 as string;
if (!t || !v1) return false;
const skew = Math.abs(Date.now() / 1000 - Number(t));
if (skew > 300) return false; // 5 min tolerance
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}Verificar la firma (Python)
import hmac, hashlib, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t, v1 = parts.get("t"), parts.get("v1")
if not t or not v1: return False
if abs(time.time() - int(t)) > 300: return False
expected = hmac.new(
secret.encode(),
f"{t}.".encode() + raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, v1)Reintentos
Si tu endpoint no responde con 2xx en 10s, reintentamos hasta 5 veces con backoff: 1 min → 5 min → 30 min → 2 h → 12 h. Después marcamos el delivery como fallido.