Supply chain webhooks
Team-tier accounts can register HTTPS endpoints that receive a signed POST when Attestd confirms a supply chain compromise on a monitored package. Use webhooks to trigger internal alerts, block deploys, or notify on-call without polling the API.
Register an endpoint
Webhooks require the Team plan. Register endpoints in the portal webhooks page or via the API. Each subscription needs an HTTPS URL and a signing secret (16 to 64 characters). Up to 5 active subscriptions per account.
curl -X POST "https://api.attestd.io/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/attestd",
"secret": "your-signing-secret-min-16-chars",
"events": ["supply_chain.compromise"]
}'See the API reference for list and delete endpoints.
Event payload
Attestd POSTs JSON with Content-Type: application/json. The body matches what the delivery worker enqueues on a real compromise:
{
"event": "supply_chain.compromise",
"package": "langchain",
"version": "0.1.20",
"ecosystem": "pypi",
"source": "osv",
"malware_type": "malicious_publish",
"description": "Malicious code in langchain (PyPI)",
"advisory_url": "https://osv.dev/vulnerability/MAL-2024-1234",
"osv_id": "MAL-2024-1234"
}Field semantics:
eventis alwayssupply_chain.compromise.package,version, andecosystemidentify the compromised release.sourceis the detection source (for exampleosv).malware_type,description,advisory_url, andosv_idcome from the incident record and may be null.
The portal "send test" button queues a synthetic delivery with source: "test":
{
"event": "supply_chain.compromise",
"package": "langchain",
"version": "0.1.20",
"ecosystem": "pypi",
"source": "test",
"malware_type": null,
"description": "This is a test delivery from Attestd.",
"advisory_url": null,
"osv_id": null
}Signature verification
Each delivery includes X-Attestd-Signature: sha256=…. The value is HMAC-SHA256 over the raw request body (compact JSON, sorted keys) using your signing secret. Verify before acting on the payload.
Python
import hashlib
import hmac
def verify_attestd_webhook(body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)Node.js
import crypto from "node:crypto";
function verifyAttestdWebhook(body: Buffer, signatureHeader: string, secret: string): boolean {
const expected =
"sha256=" +
crypto.createHmac("sha256", secret).update(body).digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}Retries and constraints
- Deliveries run on a 60-second worker cycle.
- Failed deliveries retry up to 5 attempts while status remains pending.
- Endpoint URLs must use HTTPS. Credentials in the URL are rejected.
- Private, loopback, and reserved IP ranges are blocked at registration and send time.
- Redirect responses (3xx) are not followed.
- User-Agent is
Attestd-Webhooks/1.0.