Security & Compliance — @kaltura/intelligent-agents
This SDK is built for enterprise and government deployments. It is secure by default and low-friction by design: the safe path is the clear path. Where strict compliance would otherwise hurt usability, the SDK keeps the ergonomic default and gives you a config knob plus a compliance note to tighten it.
- No runtime dependencies, no install scripts. The SDK is sourced directly from git (
src/), not a package registry, so there's zero transitive supply-chain surface. Enforced in CI. - All cryptography is delegated to the platform. The SDK never rolls its own crypto: TLS, DTLS-SRTP (the encryption protocol securing WebRTC audio and video), and base64 come from the host (Node
tls/crypto, browser WebCrypto/TLS). Run Node/OpenSSL in FIPS mode and a FIPS-validated OS/browser to operate in a FIPS-validated configuration (NIST SC-13). - Secrets never reach the client. The Admin Secret lives only server-side, in
Management. The browserKalturaAvatarSessiontakes only a short-lived, entitlement-ON conversation token.
Framework crosswalks map the SDK control-by-control to HIPAA, HITRUST, the OWASP LLM/Agentic Top 10, and avatar/deepfake/voice-clone law (EU AI Act Art. 50, NO FAKES, CA SB 1001, BIPA, C2PA). See the framework crosswalks section below, which also includes a copy-paste secure production baseline config.
Reporting a vulnerability
Email security@kaltura.com with details and a PoC if available. Please do not open a public issue for an undisclosed vulnerability. We acknowledge within a few business days and coordinate disclosure (NIST IR-6 / SI-2 is the operator's reporting duty; this is the vendor contact).
Table of contents
- AI-application controls
- KS guidance for agents
- Token lifecycle
- Audit logging
- Transport security
- Browser hardening
- Isolation & multi-tenancy
- Supply-chain integrity
- Shared-responsibility control matrix
- FIPS mode
- Data residency
- Framework crosswalks
- HIPAA
- HITRUST CSF
- OWASP Top 10 for LLM Applications
- OWASP Agentic
- Avatar / digital-human / deepfake / voice-clone
- Secure production baseline
AI-application controls (OWASP LLM/Agentic; HIPAA technical safeguards)
Beyond the platform controls below, the SDK exposes developer-friendly guardrails for the AI/agent layer, detailed in the framework crosswalks below. Most require you to opt in by passing a callback or option. Two controls run automatically, regardless of configuration. The idle-timeout auto-logoff defaults to 900000 ms (15 minutes); pass 0 to disable it. The AI-disclosure event fires before the avatar's first words on every connect.
- Output handling (LLM05). Opt-in:
safeUrl,safeText,renderSafeLink(DOM-built, scheme-checked, neverinnerHTML). Call these yourself when rendering avatar text. On by default: inbound clamping of captions/segments. - Input guardrail (LLM01). Opt-in:
onBeforeSend(text, ctx)may transform or block a turn. It's a no-op until you pass it. - Agentic gate (LLM06 / ASI 01-02). Opt-in:
onAgentAction(action)and the declarativeagentActionspolicy. Always available: the read-onlycapabilitiessurface and thestop()kill switch. - Consumption valve (LLM10). Opt-in:
maxTurnsPerMinute(unlimited until you set it). - HIPAA technical safeguards. On by default:
idleTimeoutMsauto-logoff (164.312(a)(2)(iii)), 900000 ms (15 minutes); pass0to disable. Opt-in: the opaquesubjectIdunique-user-id (164.312(a)(2)(i)). Content-free turn audit events (164.312(b)) fire automatically once you wireonAuditEvent. - Avatar/deepfake. On by default: disclosure-before-speech with
synthetic/provenancedata, fired before the avatar's first words on every connect.getDisclosure()is queryable any time. Opt-in:requireDisclosureAck(also a biometric-consent gate) and an optionalconsentRefon voice/visual cloning.
KS (Kaltura Session) guidance for agents (AC-3 / AC-6 / IA-2)
A KS carries the privileges that decide what it can do. The full privilege reference is Kaltura's own docs, not this file. See Kaltura API Authentication and Security for that. What follows is only what matters for agent/avatar deployments.
| Token | Mint with | Privilege | Entitlement | Typical use |
|---|---|---|---|---|
| admin | sessions.createAdminToken() |
disableentitlement |
OFF | Management-plane calls (provisioning, config), server-side |
| conversation / agent | sessions.createConversationToken() / createAgentToken() |
geniegpcid:<configId> / agentid:<id> |
ON | The token your server hands a live avatar/chat session |
| widget | sessions.createWidgetToken({widgetId}) |
server-derived | ON | Public, secret-free anonymous embed, safe to mint straight from the browser |
Default recommendation: mint conversation/agent/widget tokens for anything reaching a browser, and keep admin tokens server-side. createConversationToken/createAgentToken refuse extraPrivileges that disable entitlement. Neither method can be tricked into minting an entitlement-bypassing token. This is tested and gated (test/unit/scope-guard.test.js, test/integration/sessions.test.js).
Whether a given browser session should instead carry broadened (entitlement-bypassing) access is an application-level decision you make when you mint that session's token server-side. This SDK doesn't enforce it on the client.
A real KS's privileges are AES-encrypted with the partner secret and are not client-readable. inspectKs() reports disableEntitlement: null for a real token (see src/management/ks-inspect.js). So a client-side check would be inert for production tokens, and isn't attempted.
Token lifecycle (RFC 9700 OAuth 2.0 Security BCP; NIST AC family)
-
Short-lived by default: browser-bound tokens (
conversation/agent) default to 30 minutes, admin to 1 hour. Short TTL is the primary revocation lever for a stateless KS (RFC 9700 §6.1). Override per call withttlSeconds. Absurd lifetimes on browser-bound kinds are rejected (ttl_too_long). UX note: "refresh" means your server re-mints a fresh short token, and the browser callssession.setToken(freshKs)to rotate mid-session without a reconnect. -
Least privilege / binding (RFC 9700 §2.3, §4.10): tighten a token with the structured
restrictionsoption instead of hand-crafting privilege strings.{ role, actionsLimit, ipRestrict, uriRestrict, sessionGroupId }compiles to the matching Kaltura privileges (setrole/actionslimit/iprestrict/urirestrict/sessionid). Defaults stay wide-open so nobody is surprise-locked out. Tightening is opt-in. -
Active revocation (RFC 9700 §5.2.1.1; SOC 2 CC6.2/CC6.3):
sessions.revoke(tokenOrKs)ends a leaked token now (Kalturasession/end). Mint a family withrestrictions.sessionGroupIdso revoking any member is intended by design to end the whole family. The SDK checks that the KS carries the matching privilege string, but the server-side cascade itself is outside its control. Returns a_metarevocation receipt. -
Vault/KMS (NIST IA-5): pass
getAdminSecret: () => fetchFromVault()to fetch the secret per-mint instead of holding it; it is never stored as an enumerable field. -
Incident runbook for revoking a leaked conversation token:
await management.sessions.revoke(leakedKs); // or revoke(token) // if minted with restrictions.sessionGroupId: revoking any member is // intended by design to end the whole family (server-side behavior).
Audit logging (NIST AU-2 / AU-3 / AU-12; OWASP Logging; SOC 2 CC7)
The SDK is an event emitter, not a logging framework. Pass onAuditEvent to Management and/or KalturaAvatarSession to receive discrete, already-redacted, structured AuditEvent objects, and route them into your SIEM. This is opt-in: no event fires until you pass this hook.
new Management({ partnerId, adminSecret, onAuditEvent: (e) => siem.write(e) });
Event catalog
| Event | Fires when |
|---|---|
token.mint |
A KS is minted (admin, conversation, agent, or widget) |
token.revoke |
sessions.revoke() ends a token |
token.refresh |
setToken() rotates a live session's token |
guard.reject |
A call is rejected for carrying the wrong token kind (e.g. an admin token where a conversation token was required) |
auth.fail |
A request returns HTTP 401 or 403 |
session.connect |
KalturaAvatarSession finishes connecting |
session.disconnect |
KalturaAvatarSession disconnects |
session.timeout |
The idle timeout fires and auto-disconnects the session |
guardrail.block |
onBeforeSend or onAgentAction blocks a turn or action |
rate.limit |
maxTurnsPerMinute rejects a turn |
turn.user_captured |
The user's speech or text turn is captured |
turn.avatar_spoke |
The avatar starts speaking a turn |
tool.invoke |
A client-side tool call is invoked (from user text or an agent action) |
tool.ack |
The app ACKs a client-side tool call via respondToTool() |
tool.spiral_detected |
The soft tool-call-spiral threshold trips for the current turn |
tool.spiral_hard_recovery |
The hard tool-call-spiral limit trips and the session force-reconnects |
agent.action.allow |
onAgentAction allows an agent-initiated action |
agent.action.deny |
onAgentAction denies an agent-initiated action |
clone.consent |
A consentRef is recorded on a voice/visual clone upload |
whep.release |
The WHEP (WebRTC-HTTP Egress Protocol) video resource fails to release cleanly on disconnect |
session.complete |
The session-completion signal (POST /thread/session_completed) fires on disconnect, tab-close, backgrounding, or bfcache freeze. It reuses the session's own conversation KS and mints no new credential. action carries the trigger reason (disconnect, pagehide, hidden_grace, suppressed:peers=N, …). See System Internals Reference § Session-completion signal |
Event fields
Every event carries this AU-3 content shape:
| Field | Type | Description |
|---|---|---|
ts |
string | ISO-8601 UTC timestamp |
type |
string | One of the event names in the catalog above |
severity |
string | info, warning, or error |
outcome |
string | success or fail |
requestId |
string | Correlation id, reused from the triggering call |
actor.partnerId |
string | Kaltura partner id |
actor.subjectId |
string | Opaque operator-supplied user id, if set |
actor.kind |
string | Token kind (admin / conversation / agent / widget) |
actor.entitlementEnforced |
boolean | Whether entitlement was ON for this actor |
action |
string | The specific action taken |
scope |
string | The privilege string in effect, one-lined |
reason |
string | Failure reason, if any |
source |
string | Which SDK entry point emitted the event |
_meta |
object | Provenance receipt |
Guarantees
- The raw KS is never included in an event. Only its kind and scope are.
- Free-text fields are stripped of CR/LF (CWE-117 log-injection guard).
- A throwing SIEM sink can never break a mint or a live turn. Event emission is crash-safe.
- This audit stream is distinct from the chatty debug
loggerand is never gated behind a debug level.
Transport security (NIST SC-8; OWASP WSS/TLS)
KalturaAvatarSessionrejects non-TLSconversationManagerUrl/srsBaseUrl(insecure_transport).- Loopback and private hosts (
localhost/127.0.0.1, RFC 1918 ranges, link-local, and their IPv6 equivalents; seeisPrivateOrLoopbackHostinsrc/core/net-guard.js) are allowed for dev, with a loud one-time warning. - Cleartext to a public host requires an explicit
allowInsecureTransport:true(dev/test only, never production). - Prefer server-minted ephemeral TURN credentials (
turnCredentialsfrom appInit, RFC 7635) over the static fallback. The SDK warns when it falls back.
Browser hardening (OWASP ASVS / WebSocket CS)
-
Memory-only token: the SDK keeps the token in a non-enumerable instance field and drops it on
disconnect(). Do not put a conversation token inlocalStorage/sessionStorage(XSS-exfiltratable). Pass it directly and re-mint from your server on reload. -
No token in URLs: tokens travel only in the socket
authfield or theAuthorizationheader, never a query string (OWASP API2:2023). -
Prototype-pollution guard:
setDynamicPromptdata is scrubbed of__proto__/constructor/prototypebefore it touches the wire. -
CSP: the SDK uses no
eval/new Function. A working policy sets:connect-srcto your live-session control-plane host (conversationManagerUrl), the WHEP video-egress host (srsBaseUrl), and your TURN hostmedia-src blob:script-srcto your injected socket.io origin, pinned with SRI (see the README's "Injecting socket.io securely")
Also set
frame-ancestorson the embedding page. A mic-capable widget needs anti-clickjacking headers. -
AI disclosure (EU AI Act Art. 50): a
disclosureevent fires before the avatar's first words.requireDisclosureAckholds the avatar greeting untilacknowledgeDisclosure(). Note: ASR (Automatic Speech Recognition, the mic-to-text channel) connects before disclosure, so obtain consent beforeconnect()in IL/TX/WA.
Isolation & multi-tenancy (NIST SC-4 / AC-6(4))
No SDK module holds credential or tenant state at module scope. The admin secret, KS, and partnerId live only as (non-enumerable) instance fields. A single process can safely run N Management and M KalturaAvatarSession instances for different tenants, each with fully independent tokens, transports, and teardown. Nothing is shared or global (tested in test/unit/isolation.test.js).
Supply-chain integrity (SLSA / OpenSSF / EO 14028)
- Zero runtime dependencies, no install lifecycle scripts (CI-enforced).
- No registry publish step. The SDK is consumed straight from its git tags (
src/, imported by path or served via jsDelivr's GitHub CDN once the repo is public). There is no npm package, and so no registry-side supply-chain surface to audit.
Shared-responsibility control matrix (NIST 800-53)
The SDK generates and protects the records and enforces the client-side controls below; the operator owns storage-side controls a client library cannot provide (retention, tamper-evidence, non-repudiation).
| Control | Family | SDK provides | Operator responsible |
|---|---|---|---|
| AC-3, AC-6, IA-2 | Access / least privilege | Two-token invariant; client can't mint admin tokens; structured restrictions |
Role/entitlement config in Kaltura |
| AC-12 | Session termination | Short TTLs; revoke(); disconnect() drops token + transports |
Session-timeout policy |
| AU-2, AU-3, AU-12 | Audit generation/content | Structured, redacted, correlated AuditEvents via onAuditEvent |
Wire the hook to a SIEM |
| AU-4, AU-9, AU-10, AU-11 | Audit storage/integrity/retention | None | Tamper-evident storage, non-repudiation, retention |
| SC-8 | Transmission confidentiality | https/wss enforced; cleartext rejected | TLS termination, cert management |
| SC-13 | Validated cryptography | Delegates to platform TLS/WebCrypto | Run Node/OS/browser in FIPS mode |
| SC-4 | Info in shared resources | Per-instance isolation; non-enumerable secrets | Process/tenant separation |
| SI-10 | Input validation | Inbound payload validation; prototype-pollution scrub | None |
| IR-6, SI-2 | Incident/flaw response | Security contact; coordinated disclosure | US-CERT/agency reporting timelines |
| GDPR Art. 17 | Right to erasure | threads.delete() and knowledge.deleteRecord() (management API) |
threads.delete() soft-deletes immediately, with a scheduled infra-level purge erasing the data later. knowledge.deleteRecord() refuses while an intellect still references the record ({force:true} bypasses). A lifecycle rule's sendInsightEmail action delivers thread-derived content to an operator-supplied recipients list BEFORE any delete. That copy has already left the Kaltura boundary into a third-party mailbox and is outside threads.delete()'s erasure reach. Treat the recipient list as a data-processing decision under your own retention/consent obligations. |
FIPS mode (how-to)
# Node with an OpenSSL FIPS provider:
node --enable-fips your-server.js
# or via OpenSSL 3 FIPS provider config (OPENSSL_CONF / fipsmodule.cnf)
In the browser, FIPS validation is a property of the OS/browser crypto module. Deploy on a FIPS-validated platform; the SDK adds no non-validated crypto.
Data residency (SC-7)
The SDK is a thin client. It contacts only the Kaltura endpoints you configure (agenticUrl/genieUrl/ovpUrl/conversationManagerUrl/srsBaseUrl/turnServerUrl). There is no telemetry, analytics, or hidden beacons. Point every URL at your in-boundary (e.g. US-Gov) hosts to keep all data within your authorization boundary.
This residency guarantee covers the SDK's own configured endpoints only. A lifecycle rule's sendInsightEmail action is a server-side, operator-configured email delivery of thread-derived content to an arbitrary recipients list. It has no residency control and isn't covered by the URL-pinning above.
A deployment that must protect PHI/PII boundaries and uses this action is responsible for its own recipient vetting and residency review. The HIPAA BAA (below) names avatar/ASR/TTS/brain subprocessors, not an email-delivery subprocessor for insight content.
Framework crosswalks
This section maps the SDK to the specific frameworks an enterprise, government, or healthcare buyer audits against. It's the companion to the posture and NIST 800-53 matrix above.
Shared responsibility: a client SDK can implement technical controls and generate the records, but it cannot sign a contract, retain logs, or authenticate the human user. Each table marks SDK (the library provides it) vs Operator (your duty, fed by the SDK's hooks/events).
HIPAA (45 CFR Part 164)
Gating item: Kaltura offers a Business Associate Agreement, covering Kaltura and its avatar/ASR/TTS/brain subprocessors, as required before any PHI flows (164.308(b), 164.502(e)). Contact your Kaltura Account Manager or Customer Success Manager to execute one.
| Safeguard (CFR) | SDK provides | Operator responsible |
|---|---|---|
| 164.312(e)(1)/(e)(2) Transmission security | https/wss enforced (insecure_transport); WebRTC media is DTLS-SRTP; crypto delegated to platform TLS |
TLS termination, cert management |
| 164.312(b) Audit controls | onAuditEvent (token + auth + guard lifecycle) and content-free PHI-exchange turn events (turn.user_captured, turn.avatar_spoke, session.timeout), never content |
Wire to SIEM; review (164.308(a)(1)(ii)(D)) |
| 164.312(a)(2)(iii) Automatic logoff | idleTimeoutMs (default ON, 900000 ms) → disconnect() + idleWarning + session.timeout audit |
Choose the timeout per care setting |
| 164.312(a)(2)(i) Unique user identification | Optional opaque subjectId threaded onto every AuditEvent |
Supply an opaque id (never the patient's name/PHI) |
| 164.312(a)(1) Access control | Two-token invariant; entitlement-ON conversation tokens; least-privilege restrictions |
Role/entitlement config in Kaltura |
| 164.312(d) Person/entity authentication | Authenticates the session (KS), minted server-side under your control | Proof the patient before minting the conversation token; bind via subjectId |
| 164.502(b) Minimum necessary | Redaction chokepoint; SDK persists no transcripts/captions/screenshots | Don't persist captions/screenshots beyond minimum necessary; apply retention |
| 164.402 Breach / safe harbor | PHI encrypted in transit + no token/PHI at rest → supports the encryption safe harbor for the SDK-controlled path | At-rest encryption; breach detection + 164.404/164.410 notification |
| 164.316(b)(2) Retention | Emits the records | Tamper-evident storage + 6-year retention |
PHI note: a patient may speak PHI to the avatar, so captions, transcripts, screenshots, and request-variable context (setDynamicPrompt's page_context) can carry PHI. The SDK surfaces these to your app but persists none of them. Treat them as PHI in your app. Remember that request variables persist on the conversation thread server-side for the rest of the thread.
HITRUST CSF (incl. the AI Security Assessment)
The SDK is an AI Application Provider component you can largely inherit in a HITRUST assessment. Kaltura's platform posture is the upstream inheritance source.
| HITRUST AI requirement | SDK provides | Operator / inherited |
|---|---|---|
| Encrypt traffic to/from the model | https/wss enforced; DTLS-SRTP | Platform/TLS |
| Restrict access to interact with the model | Two-token invariant; entitlement ON; revoke() |
Identity proofing |
| Log AI inputs/outputs (AI.PI.a) | Security + turn audit via onAuditEvent (content-free by default) |
SIEM storage/retention |
| Model rate limiting / DoS | Client-side maxTurnsPerMinute valve |
Authoritative server-side quota (inherited) |
| Humans can intervene (AI.NI.a, non-inheritable) | stop() / disconnect(), revoke(), barge-in (interrupt()), requireDisclosureAck, onAgentAction veto |
Wire at least one to a visible UI control |
| Output filtering / prompt-injection | safeUrl/safeText/renderSafeLink (output); onBeforeSend hook (input) |
Model-side guardrails (inherited); red-team the intellect (the SDK's term for the agent's configured brain, its prompts, tools, and knowledge linkage) |
| AI supply chain | Zero deps, no install scripts, no registry publish step | Due-diligence review |
| AI transparency to end-user | Disclosure-before-speech + getDisclosure() |
Render it accessibly |
| Audit retention / tamper-evidence | Emits records | 6-year-or-longer tamper-evident storage |
Prompt-injection note: the prototype-pollution scrub on
setDynamicPrompt/inbound is object-injection defense, not prompt-injection defense.redact()is log-scoped, not an output content filter. Don't pass unsanitized end-user text intosetDynamicPromptor any request variable. Request variables are thread-persistent, so a poisoned value outlives its turn and keeps interpolating into prompts and server-side tool calls for the rest of the thread. Instruction/data separation, source allow-listing, and model guardrails are operator/platform duties.
OWASP Top 10 for LLM Applications (2025)
| Item | Status |
|---|---|
| LLM01 Prompt Injection | onBeforeSend(text, ctx) input-filter hook (block/transform). Model-side detection is operator/platform. |
| LLM02 Sensitive Info Disclosure | Redaction of secrets in logs/audit. onBeforeSend lets you mask outbound PII. Never put secrets in any request variable, including the page_context payload setDynamicPrompt sends. Values persist on the thread and interpolate into prompts and server-side tool calls. |
| LLM03 Supply Chain | Zero runtime deps, no install scripts, no registry publish step, SRI on the injected socket.io (CI-gated). |
| LLM05 Improper Output Handling | safeUrl (scheme allow-list), safeText, renderSafeLink (DOM-built, never innerHTML), inbound clamping of captions/segments. Treat avatar text/GenUI (the SDK's on-screen widget layer: flashcards, forms, images rendered from brain output) as untrusted. |
| LLM06 Excessive Agency | onAgentAction gate + declarative agentActions policy + capabilities surface + requireDisclosureAck/requireActionAck HITL. |
| LLM07 System-Prompt Leakage | Documented: never embed secrets/authz rules in the provisioned prompt or any request variable (setDynamicPrompt included). |
| LLM10 Unbounded Consumption | Client maxTurnsPerMinute valve (rate_limited); server quota is authoritative. |
| LLM04 / LLM08 / LLM09 | Operator: data/model poisoning, RAG/embedding ACLs, and misinformation/overreliance UX are out of a client SDK's control. |
Bounded-parser contract: nav/action commands parsed out of avatar text must be bounded allow-lists, never eval/dispatch of arbitrary strings. parseSlideNumber (integer-bounded, range-checked) is the template.
OWASP Agentic (Agentic Security Initiative / Top 10 for Agentic Apps)
The avatar's brain is an agent (navigates, renders GenUI, captures leads, searches knowledge). The SDK is the client boundary where agent-initiated actions surface.
| Threat | Control |
|---|---|
| ASI 01 Goal Hijack / ASI 02 Tool Misuse | onAgentAction(action) chokepoint. Every agent-initiated action (navigate/render-genui/structured-data-form/…) passes through it before taking effect. Veto via false/throw. Operator (server-side api/code/csv tools): these fire server-to-server, outside the SDK's reach. Independently authorize each call against the caller's real session/permissions. Never treat model/system-prompt tool scoping, or a client-suppliable request_vars value, as an authorization claim. See Backend API Reference § Tools. |
| ASI 03 Identity & Privilege Abuse | Scoped, entitlement-ON, short-TTL, revocable token; least-privilege restrictions; agentActions policy (e.g. navigate:'off'). |
| ASI 06 Memory & Context Poisoning | Presenter session memory is bounded and operator-cleared via clearMemory(). Persisted memory is replayed context. The operator owns the storage choice. |
| ASI 08 Cascading Failures | Reconnect-window bound, media-recovery escalation, brain-liveness watchdog, client rate valve. |
| ASI 09 Human-Agent Trust | Disclosure-before-speech + getDisclosure(); requireDisclosureAck. |
| T8 Repudiation | agent.action.allow/agent.action.deny audit events. |
| ASI 05 RCE | The SDK never evals agent output; nav uses a bounded parser. |
Avatar / digital-human / deepfake / voice-clone
| Obligation | Citation | Status |
|---|---|---|
| AI-interaction disclosure | EU AI Act Art. 50(1); CA SB 1001 (BOT Act); Utah AI Policy Act; Colorado AI Act | SDK: disclosure fires before first avatar speech + getDisclosure() queryable any time. Operator: render it accessibly (ARIA live region, not color-only; WCAG 2.1 SC 4.1.3). |
| Synthetic-media output marking | EU AI Act Art. 50(2); Recital 133; C2PA 2.x | SDK: disclosure.synthetic:true + provenance{generatedBy,voice,sessionId}. Operator/Platform: durable machine-readable marking (C2PA manifest) of the live media stream is server-side; stamp client-captured screenshots/recordings with an "AI-generated" assertion. |
| Deepfake disclosure (deployer) | EU AI Act Art. 50(4); Recital 134 | Operator (deployer) discloses manipulated content; SDK's disclosure supports it. |
| Bot identification | CA SB 1001 §17940 | SDK disclosure + persistent getDisclosure(). |
| Biometric notice + consent | BIPA 740 ILCS 14/15; TX CUBI §503.001; WA RCW 19.375 | The mic uplink may capture a "voiceprint." SDK: requireDisclosureAck can gate the mic until acknowledged. Operator: capture written-equivalent consent in IL/TX/WA before mic start. The avatar face/voice handling is operator/platform. |
| Voice/likeness clone consent | NO FAKES Act; TN ELVIS Act; CA AB 1836/2602; FTC impersonation rule | SDK: Management voice/visual provisioning accepts optional consentRef stored in data._consent on the returned catalog item. A clone.consent audit event is emitted. Operator: obtain and retain the source individual's consent. |
| Emotion / biometric categorisation notice | EU AI Act Art. 50(3) | Operator, if such features are enabled. |
Secure production baseline (CM-6)
Copy-paste hardened configuration for a regulated deployment:
// Server: Management
const mgmt = new Management({
partnerId, getAdminSecret: () => vault.fetch('kaltura-admin'), // or adminSecret
onAuditEvent: (e) => siem.write(e),
});
const token = await mgmt.sessions.createConversationToken({
configId, ttlSeconds: 1800, // short-lived (RFC 9700)
restrictions: { actionsLimit: 200, sessionGroupId: caseId }, // least privilege + revocable family
});
// Browser: Experience
new KalturaAvatarSession({
token, conversationManagerUrl, srsBaseUrl, turnServerUrl, // all https/wss
turnCredentials, // ephemeral (RFC 7635), not the static fallback
allowInsecureTransport: false, // never true in production
requireDisclosureAck: true, // EU AI Act / biometric jurisdictions
idleTimeoutMs: 900000, // HIPAA auto-logoff
subjectId: opaqueUserId, // HIPAA unique-user-id (never PHI)
maxTurnsPerMinute: 30, // LLM10 valve
onBeforeSend: (t) => myGuardrail(t), // LLM01 input filter
onAgentAction: (a) => myPolicy(a), // LLM06 / Agentic action gate
onAuditEvent: (e) => siem.write(e),
});
Plus: pin the injected socket.io with SRI; set a strict CSP (connect-src your control-plane, WHEP and TURN hosts; media-src blob:; no inline script/unsafe-eval) and frame-ancestors on the embedding page; render the disclosure accessibly.