Embed Widgets: Security & Compliance
CSP directives, SRI hash pinning, sub-processor declaration, data residency, GDPR posture, and how to report vulnerabilities.
Content-Security-Policy#
Add the following directives to your CSP. The widgets work without unsafe-inline or unsafe-eval — they don't use eval(), new Function(), or dynamic import() of untrusted URLs.
style-src 'unsafe-inline'? The widgets inject scoped <style> tags at mount time (namespaced with aforo-w-*classes) so customers don't need to import a separate CSS file. We're actively evaluating a CSP-nonce path for v1.1 — track FR-SEC-17 in the roadmap.SRI hash pinning#
Subresource Integrity (SRI) hashes are published per version. Pin the loader script via the integrity= attribute so the browser refuses to execute a tampered bundle.
Live SRI manifest
Fetch the current hashes from embed.aforo.ai/v1/sri.json. Shape:
Pinning
Per-widget bundles are lazy-fetched by the loader using the hashes embedded in the SRI manifest — you don't need to pin them individually. If the manifest itself were tampered, the loader-level integrity check would still fail.
HTTPS only#
The loader refuses to bootstrap on http:// pages — you'll see a console error and no widgets will mount. This is a hard guard (FR-TIER-12) to prevent token leakage over plaintext.
Localhost is exempt (so http://localhost:3000 works during dev) but any other plaintext host is rejected.
Sub-processors#
For GDPR Article 28 record-keeping, the plugin tier introduces these sub-processors beyond Aforo's platform-wide list:
The full Aforo sub-processor list is at .
Data residency#
The CDN serving embed.aforo.ai uses CloudFront edge locations globally — your customers fetch bundles from their nearest edge. The bundle content is identical worldwide; only static JavaScript is served from the CDN.
Authenticated API traffic (api.aforo.ai) and customer data are processed in Aforo's primary region per your tenant's configured residency. Today: US East (Virginia). EU and APAC residency are documented in .
GDPR + RTBF#
The widget SDK is a thin client — it doesn't persist customer data in the browser beyond the in-memory session JWT (cleared on tab close) and a 30-second result cache in InvoiceList (cleared on unmount). When you submit a Right-to-be-Forgotten request via Aforo's DSR queue, the customer's data is purged platform-wide; the next time their browser mounts a widget, the bridge exchange creates a fresh (or rejects the request, depending on your privacy mode).
See for the full DSR lifecycle.
Vulnerability reporting#
Report vulnerabilities privately to security@aforo.ai. Do not file public GitHub issues for security reports.
- Acknowledgement within 2 business days
- Initial triage within 5 business days
- Critical fixes ship in <72h, high within 14 days
- Coordinated disclosure with 90-day default embargo
Full security policy: SECURITY.md.