Skip to main content

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, TTL PREVIEW_TOKEN_TTL_SECONDS (default 1 h).
  • Download tokens — signed with DOWNLOAD_SIGNING_SECRET, TTL DOWNLOAD_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:

ModeWho can viewNotes
unlisted (default)Anyone with the shareable linkOptional per-page password unlock
authenticatedOnly authenticated IntelliAsk usersRequires 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 from IDENTITY_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.

NamePurposeDefault
SENSITIVE_DATA_GUARD_ENABLEDMaster switch for the guardtrue
SENSITIVE_DATA_GUARD_AI_ENABLEDUse an AI classifier in addition to deterministic rulesfalse
SENSITIVE_CONFIDENCE_THRESHOLDMinimum confidence to flag a field0.6
SENSITIVE_DEFAULT_RETENTION_DAYSDefault retention for sensitive data7
SENSITIVE_MAX_RETENTION_DAYSHard cap on retention7
SENSITIVE_MIN_PASSWORD_LENGTHMinimum length for a protecting password12
SENSITIVE_UNLOCK_RATE_PER_MINUnlock attempts per client per minute5

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/https hosts — 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