Reference

Security & Compliance — @kaltura/intelligent-agents

Defaults are secure. Where a strict setting would hurt usability, the SDK keeps a usable default and gives you an option to tighten it, noted in this file.

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.

Table of contents

AI-application controls (OWASP LLM/Agentic; HIPAA technical safeguards)

Guardrails for the AI/agent layer. Most are opt-in: pass the callback or option. Framework mapping: framework crosswalks.

KS (Kaltura Session) guidance for agents (AC-3 / AC-6 / IA-2)

A KS carries the privileges that decide what it can do. Full privilege reference: Kaltura API Authentication and Security.

Token Mint with Privilege Entitlement Typical use
admin sessions.createAdminToken({ userId }) disableentitlement OFF Management-plane calls (provisioning, config), server-side
conversation / agent sessions.createConversationToken({ configId, userId }) / createAgentToken({ agentId, userId }) setrole:PLAYBACK_BASE_ROLE, geniegpcid:<configId>, and agentid:<id> (agent tokens, or conversation tokens minted with agentId) ON The token your server hands a live avatar/chat session. A user session (KS type 0) by default. See Session type
widget sessions.createWidgetToken({widgetId}) server-derived ON Public, secret-free anonymous embed, safe to mint straight from the browser. See Session type

For anything that reaches a browser, mint conversation/agent tokens (with a per-user userId) or widget tokens. Keep admin tokens server-side. createConversationToken/createAgentToken reject extraPrivileges that disable entitlement (entitlement_violation). Which of the two to use: Conversation token or agent token?.

Admin-type tokens (createAdminToken(), or sessionType: 'admin' on a conversation/agent token) are for your server. Your server decides at mint time what reaches a browser. The browser SDK can't check it: a real KS's privileges are encrypted, so inspectKs() reports disableEntitlement: null.

Session type

createConversationToken() and createAgentToken() mint a user session (KS type 0) by default: setrole:PLAYBACK_BASE_ROLE, entitlement ON. sessionType: 'admin' mints an admin-level session (KS type 2, no forced role), limited only by the role and privileges you set. createAdminToken() is always type 2 with disableentitlement, server-side only. Every type 2 mint needs a userId, which becomes the owner of anything the token creates. Minting options: Authentication.

What each token can reach:

Token Threads OVP admin APIs
Admin type (type 2): createAdminToken(), or sessionType: 'admin' Every user's threads Yes, within the role and privileges you set
Conversation/agent with userId (user session) Own threads: read, continue, list, delete No
Conversation/agent without userId One identity for all holders. Read, list and delete return 403 No
Widget Same as without userId No

subjectId is for audit only. It is not an access boundary. Use userId on the token for that.

Token lifecycle (RFC 9700 OAuth 2.0 Security BCP; NIST AC family)

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. A failed conversations.stream request fires it for any error status
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
turn.converse KalturaChatSession.sendText() completes or fails
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 README.md § Ending a conversation cleanly

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. Audit only, not an access boundary
actor.kind string Token kind (admin / conversation / agent / widget)
actor.sessionType string user or admin. Not set for widget tokens
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
target string Resource acted on, if any
reason string Failure reason, if any
source string Which SDK entry point emitted the event
expiresAt number Unix epoch seconds. Set on token.mint only
_meta object Provenance receipt

Guarantees

Transport security (NIST SC-8; OWASP WSS/TLS)

Browser hardening (OWASP ASVS / WebSocket CS)

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.

Supply-chain integrity (SLSA / OpenSSF / EO 14028)

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; user-session tokens by default (Session type); 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() (admin token, or a per-user token for its own threads; deletes are soft) and knowledge.deleteRecord() Emails already sent by a lifecycle rule's sendInsightEmail action are outside threads.delete()'s reach. Treat its recipients list as a data-processing decision.

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/messagingUrl/conversationManagerUrl/srsBaseUrl/turnServerUrl). There is no telemetry or hidden beacon. The optional ./experience/analytics module sends KAVA application events to analytics.kaltura.com, and only when your code calls it. Point every URL at your in-boundary (e.g. US-Gov) hosts to keep all data within your authorization boundary.

Session hosts come from appInit, not from your config. appInit returns the conversationManagerUrl, srsBaseUrl and turnServerUrl for your partner's region. Pass them to KalturaAvatarSession unchanged (new KalturaAvatarSession({ ...appInit, token: appInit.ks })). Do not hard-code them. If you omit conversationManagerUrl, the session falls back to the US host.

The region option covers the rest. It fills the four Management base URLs (agenticUrl, genieUrl, ovpUrl, messagingUrl) and the session genieUrl from one REGIONS entry. Management never falls back to another region: a service the region lacks throws region_unavailable instead of reaching a US host. region does not change the analytics host.

This residency guarantee covers the SDK's own configured endpoints only. A lifecycle rule's sendInsightEmail action sends thread-derived content to the recipients you list, and the URL-pinning above does not apply to it. Your code decides which recipients and regions are allowed. A deployment that must protect PHI/PII boundaries vets the recipients list and reviews residency before it uses this action.

Data handling and deletion

The SDK stores no conversation data itself. The one exception is Presenter session memory, which stays off unless you pass a storage object. How long Kaltura keeps data is a property of your account: ask your Kaltura Account Manager.

Every delete needs an admin token (a user-session token can also delete its own threads) and { confirmPermanent: true }.

Data Read or list Delete
Threads threads.list, get, transcript threads.delete(ids, ks, confirm). Deletes are soft: behavior and result shape
Messages messages.list, get, report No method. The SDK cannot delete a single message
Knowledge records knowledge.list, getRecord knowledge.deleteRecord(id, ks, confirm). It refuses while an intellect still lists the record, unless you pass force: true. knowledge.removeSource removes one source from a record
Agents, avatars, intellects agents.list, avatars.list, intellects.list agents.delete, avatars.delete, intellects.delete. None cascades: deleting an agent keeps its avatar and intellect
Tools, skills, secrets, catalog items, lifecycle rules, insight settings, email templates list or get on each delete on each

To erase everything for one end user, list their threads with filter.userIdEquals, then pass the ids to threads.delete. The SDK has no single call for this and no way to see when a soft delete is purged.

Framework crosswalks

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. 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 (audit only, not an access boundary) Supply an opaque id (never the patient's name/PHI)
164.312(a)(1) Access control Two-token invariant; entitlement-ON user-session tokens that reach only the userId's own threads; 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 the token with a per-user opaque userId
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.

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; per-user user sessions; 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 agent's configured 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 into setDynamicPrompt or any request variable. Request variables stay on the thread, so see Dynamic Data Injection for what that means for a poisoned value. 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.
LLM03 Supply Chain Zero runtime deps, no install scripts, no registry publish step, SRI on the injected socket.io.
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 agent output) as untrusted.
LLM06 Excessive Agency onAgentAction gate + declarative agentActions policy + capabilities surface + requireDisclosureAck 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 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 Tools and Secrets § Tools.
ASI 03 Identity & Privilege Abuse Scoped user-session token (per-user userId), entitlement ON, short TTL, revocable; 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, agent-stall 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)
  userId: opaqueUserId,                       // per-user identity: reaches only this user's threads
  restrictions: { sessionGroupId: caseId },   // revocable family
});

// Browser: Experience
new KalturaAvatarSession({
  token, conversationManagerUrl, srsBaseUrl, turnServerUrl,      // all https/wss
  turnCredentials,                            // ephemeral (RFC 7635), not the SDK default
  allowInsecureTransport: false,              // never true in production
  requireDisclosureAck: true,                 // EU AI Act / biometric jurisdictions
  idleTimeoutMs: 900000,                      // HIPAA auto-logoff
  subjectId: opaqueUserId,                    // audit only: 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.

Click to talk with Nova — she knows this whole SDK.
Nova AI assistant — knows this whole site

Nova is an AI assistant and can make mistakes. Check important details in the docs. Reloading starts a fresh chat.