ShieldLabs scores visits; your code owns the decision. Nothing here changes that: these are integration security controls, not a verdict engine. The Risk Score is
0-100 (Clean / Low / Medium / High) and you act on it in your own backend.Webhook authenticity (HMAC-SHA256)
Your webhook URL is a public endpoint. Anyone who learns it can POST to it. The only thing that proves a delivery actually came from ShieldLabs is its signature, so verify every webhook before you trust the body. The signature is theX-Shield-Signature header: sha256= plus the hex HMAC-SHA256 (a keyed cryptographic hash that only someone holding the secret can produce) of the raw request body, keyed with that endpoint’s whsec_… signing secret, constant-time compared, rejecting with 401 on a mismatch.
The exact formula, the Node, Go, and Python handlers, the raw-bytes gotcha, and idempotency on request_id all live on the webhooks page.
Key handling
Every domain has a public key, a private API key, and a secret key, scoped to that single domain. They have different trust levels. The API keys page is the full reference for which key each API uses.
The public key is meant to be visible. It ships in your page source as the
?publicKey= parameter and cannot read data, change settings, or authenticate against the Server API. A request is only accepted when the public key matches the domain it is served from, so a key lifted from your page will not work on someone else’s site.
Your server-side keys (the private API key and the secret key) authenticate the Server API. Anyone holding one can read your domain’s data, so they must never reach the browser. Webhook endpoints use separate whsec_… secrets; treat a leaked webhook secret the same way and rotate it from the dashboard.
Rotate when exposed
If a secret may have leaked (a committed.env, a log line, an offboarded teammate), rotate the domain’s key set from the dashboard right away. Rotation issues a fresh public key and secret key, shows the new secret in full once, and invalidates the old set immediately, so update the snippet and your server together. The step-by-step rotation flow, masking, and the Profile health check live on the API keys page.
Transport security (HTTPS / TLS)
Everything moves over HTTPS.- ShieldLabs hosts (
cdn.shieldlabs.ai,rest.shieldlabs.ai,webrtc.shieldlabs.ai,api.shieldlabs.ai,app.shieldlabs.ai) are served over TLS (the encryption behind HTTPS). - Your webhook callback URL must be HTTPS. It receives signed scores and identifiers, so terminate TLS in front of your handler.
- Your Server API calls must be HTTPS. They carry your server-side keys, so a plaintext request would put a credential on the wire. Always call over HTTPS (
https://account.shieldlabs.ai/…,https://api.shieldlabs.ai/…).
Payload protection (honest scope)
The snippet wraps its signal payload with AES-256-GCM (a strong symmetric encryption cipher) before POSTing it torest.shieldlabs.ai. This is worth understanding precisely, because it is easy to overstate.
The encryption key is derived from your public key, and the public key is the same value that travels in cleartext in the snippet URL. So the wrapping protects payload integrity and obfuscates it in transit on top of TLS. It is not a secret-key scheme, and it is not end-to-end encryption.
There is nothing for you to configure. The snippet handles wrapping automatically in a secure context, and the server accepts both wrapped and plain payloads. Your job is to keep the page on HTTPS so TLS does the real confidentiality work.
Data handling on your side
A few practices keep the data you exchange with ShieldLabs clean.- Pass a hashed
UserHID, never a raw identifier. When you callcheckAuthenticatedUser, send a hashed or pseudonymous account id, not a real email or user id. It is echoed back in webhooks and history, so keep it opaque. - The public key is the only credential in the browser. Identifiers like the client cookie id and session id live client-side by design and break on storage clear. The durable identity (DeviceID) and the Risk Score are derived server-side and reach you through signed webhooks and the Server API, never assembled in the page.
- Keep raw signals server-side. Read scores and signals from your verified webhook handler or the History API, and apply your allow / challenge / review / block logic in your backend. There is no in-product rules engine to leak through.
Responsible disclosure
If you find a security issue in ShieldLabs, report it privately to contact@shieldlabs.ai. Please include enough detail to reproduce it, and give us a reasonable window to confirm and fix before any public disclosure. We do not pursue good-faith researchers who follow coordinated disclosure.Security checklist
1
Verify every webhook
Constant-time compare
X-Shield-Signature against HMAC-SHA256 of the raw request body, keyed with the endpoint’s whsec_… secret. Reject with 401 on a mismatch.2
Keep the secret on the server
Secret key in an environment variable or secrets manager, never in the browser. One key set per domain.
3
Rotate on exposure
Rotate the key set the moment a secret may have leaked, then update the snippet and your server together.
4
HTTPS everywhere
Snippet pages, your callback URL, and your Server API calls all over TLS. The snippet needs a secure context to run.
5
Hash the UserHID
Send only a hashed or pseudonymous account id to
checkAuthenticatedUser.Related pages
Webhooks
X-Shield-Signature verification in Node, Go, and Python, and idempotency on request_id.API keys
Public and secret key lifecycle, masking, and rotation.
Content Security Policy
The exact
script-src and connect-src directives the snippet needs.Privacy
What is and is not collected, and who controls retention.