Supply chain webhooks
Platform Starter 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 Platform Starter. 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.