Security model
How IntelliApps protects user-generated apps and their viewers — the shared service key, stateless HMAC-signed preview/download tokens, unlisted vs authenticated publishing, the two-plane Identity Bridge, the Sensitive Data Guard, SSRF-guarded remote fetches, isolated page origins and CSP, and the non-dev refusal of placeholder secrets.
IntelliApps serves model-generated pages to real end-users, so its security model is layered: the service authenticates the platform caller, keeps no per-user session (everything is signed and time-limited), isolates each served page, scrubs sensitive data before it ever reaches the model, and refuses to boot insecurely in production.
Service authentication
Only the IntelliAsk container talks to IntelliApps, and every MCP/HTTP call carries the
shared service key as the X-App-Service-Key header. It's the
INTELLIAPPS_SERVICE_KEY on the IntelliAsk side and HTML_APP_MCP_API_KEY here — the
two must match. See
Configuration → Connecting to IntelliAsk.
Production refuses placeholder secrets
When APP_ENV is not development, the service will not start if
HTML_APP_MCP_API_KEY, PREVIEW_SIGNING_SECRET, or DOWNLOAD_SIGNING_SECRET are
left at their change-me defaults.
Stateless signed tokens
The service holds no sessions. Previews and self-contained exports are authorised by HMAC-signed, time-limited tokens instead:
- Preview tokens — signed with
PREVIEW_SIGNING_SECRET, TTLPREVIEW_TOKEN_TTL_SECONDS(default 1 h). - Download tokens — signed with
DOWNLOAD_SIGNING_SECRET, TTLDOWNLOAD_TOKEN_TTL_SECONDS(default 15 m). - Password-unlock cookies for protected published pages — TTL
PUBLISH_UNLOCK_TTL_SECONDS(default 8 h).
Because authorization is carried in the token, any replica can serve any request and tokens expire on their own.
Publish modes
PUBLISH_MODE sets how a published page is reached:
| Mode | Who can view | Notes |
|---|---|---|
unlisted (default) | Anyone with the shareable link | Optional per-page password unlock |
authenticated | Only authenticated IntelliAsk users | Requires an upstream authenticating proxy and INTELLIASK_ORIGIN; the service will not start in a non-dev env without it |
Identity Bridge
Viewer identity is split into two independent planes so an app owner can adopt strong identity for collaboration without leaking profile data into model-generated code:
- Platform plane — powers built-in collaboration (comments, presence, forms,
collections). An authenticated IntelliAsk viewer is named automatically; otherwise a
guest name is captured. Controlled by
IDENTITY_PLATFORM_DEFAULT. - App Code plane — the only identity data exposed to the generated app's own
JavaScript, and strictly opt-in per claim. An org allow-list
(
IDENTITY_APP_CLAIMS_ALLOWED) caps what an owner may ever expose; the owner then selects a subset (seeded fromIDENTITY_APP_DEFAULT_CLAIMS).
Identity is delivered to an embedded page by a signed view token (TTL
IDENTITY_VIEW_TOKEN_TTL_SECONDS, default 10 m) which the page exchanges for a
per-viewer identity cookie (IDENTITY_COOKIE_TTL_SECONDS, default 8 h). Standalone
viewers are sent through the sign-in handoff
(IDENTITY_SIGNIN_URL_TEMPLATE, or auto-derived from INTELLIASK_ORIGIN). See
Configuration → Identity Bridge.
Sensitive Data Guard
Before any dataset the model imported is stored or reflected back, the Sensitive Data Guard scans it for sensitive fields (PII, secrets) and gates access to them.
| Name | Purpose | Default |
|---|---|---|
SENSITIVE_DATA_GUARD_ENABLED | Master switch for the guard | true |
SENSITIVE_DATA_GUARD_AI_ENABLED | Use an AI classifier in addition to deterministic rules | false |
SENSITIVE_CONFIDENCE_THRESHOLD | Minimum confidence to flag a field | 0.6 |
SENSITIVE_DEFAULT_RETENTION_DAYS | Default retention for sensitive data | 7 |
SENSITIVE_MAX_RETENTION_DAYS | Hard cap on retention | 7 |
SENSITIVE_MIN_PASSWORD_LENGTH | Minimum length for a protecting password | 12 |
SENSITIVE_UNLOCK_RATE_PER_MIN | Unlock attempts per client per minute | 5 |
The guard runs deterministic rules by default; set
SENSITIVE_DATA_GUARD_AI_ENABLED=true to add an AI classifier. Retention is capped
by SENSITIVE_MAX_RETENTION_DAYS, so sensitive material ages out automatically.
SSRF-guarded remote fetches
Both the web-search image import and the BRAND_LOGO_URL fetch are performed by the
service (the build sandbox has no network). Every remote fetch:
- allows only public
http/httpshosts — private, loopback, and link-local ranges are rejected; - caps size (
MAX_ASSET_BYTES), time (ASSET_FETCH_TIMEOUT_SECONDS), and redirects (ASSET_FETCH_MAX_REDIRECTS); - restricts accepted content types to raster images
(
FETCHABLE_IMAGE_CONTENT_TYPES) — never SVG or fonts.
Set ASSET_FETCH_ENABLED=false to remove the capability entirely.
Page isolation
Each served page runs as an isolated document with a Content-Security-Policy whose
frame-ancestors is pinned to INTELLIASK_ORIGIN, so an app can be embedded only by
the IntelliAsk app and can't reach back into the platform. Generated app code sees only
the claims the owner explicitly enabled via the Identity Bridge — nothing more.
Last updated on