Splunk
Stream LeakJar webhook events into your Splunk instance via HTTP Event Collector. Events arrive as structured JSON, signed with an HMAC in the X-LeakJar-Signature header.
1. Create a HEC token in Splunk
- Splunk Web → Settings → Data Inputs → HTTP Event Collector.
- New Token. Name it
leakjar. - Source type:
_json. Index: pick one (e.g.security). - Review & Submit — copy the generated token value.
2. Add the webhook in LeakJar
In Console → Projects → Webhooks, add a webhook with:
url: https://<splunk-host>:8088/services/collector/event
events: [exposureAlert.created, exposureAlert.resolved]The signing secret shown once on creation is for HMAC verification (see below). Splunk HEC auth is a separate token that must ride in the request, so use a reverse proxy / Edge Function if you need to inject it; otherwise use Splunk's Token in URL input type instead.
3. Splunk search examples
# All resolved exposure alerts in the past 7 days
index=security sourcetype=_json event="exposureAlert.resolved"
| table _time data.email data.severity data.source
# Count critical exposures per monitored domain
index=security event="exposureAlert.created" data.severity=critical
| stats count by data.monitoredDomainIdThe webhook payload identifies the monitored domain by data.monitoredDomainId, not a domain name. Available data.* fields: id, email, source, severity, breachDate, monitoredDomainId.
4. Verify the HMAC signature
LeakJar signs every webhook with HMAC-SHA-256 over <timestamp>.<raw_body>. The signature is in the X-LeakJar-Signature header as t=<ts>,v1=<hex>.
import { createHmac, timingSafeEqual } from "crypto";
export function verify(
body: string,
header: string,
secret: string,
maxSkewSeconds = 300,
): boolean {
const parts = Object.fromEntries(
header.split(",").map((p) => p.split("=")),
);
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > maxSkewSeconds) return false;
const expected = createHmac("sha256", secret)
.update(`${t}.${body}`)
.digest("hex");
const sig = Buffer.from(parts.v1 ?? "", "hex");
const exp = Buffer.from(expected, "hex");
return sig.length === exp.length && timingSafeEqual(sig, exp);
}