MallaDocs

Security model

Sandboxed canvas, no eval, server-side secrets, row rules, rate limits and the outbound policy.

Developer guide

Malla runs untrusted content, user formulas and visitor input next to customer secrets. These are the boundaries that keep them apart.

Sandboxed canvasArtboards render on a separate origin, so user content can never reach editor sessions.
No evalExpressions are parsed and interpreted with a whitelist and hard limits.
Server-side secretsEncrypted at rest, decrypted only in the api Worker, never sent to any browser.
Row rulesEvery visitor and workflow read or write of a native table is checked.
Outbound policyServer fetches block private addresses, resolve DNS first, cap time and size.
Rate limitsLogin, sign-up, forms, queries, endpoints and integrations are limited.

Two populations, never mixed

Editor users and site visitors have separate tables, separate session cookies and separate signing keys. Editor sessions are HTTP-only, Secure, SameSite=Lax cookies with CSRF checks; passwords are hashed with scrypt. Visitor sessions are scoped to the customer’s domain and live in the site’s own database.

Authorization

  • Every api route checks the caller’s role on the site; unknown and forbidden sites both answer 404.
  • Production publishes, slug changes, domains and integration writes need an admin.
  • Realtime rooms verify a short-lived token and the page’s site; viewers are read-only and content editors may only change text.
  • Realtime validates every update against the schemas before storing or relaying it.

Expressions

No eval and no new Function. The interpreter rejects window, document, globalThis, constructor, __proto__ and prototype, has no assignment or loops, and caps source length, depth, evaluated nodes, string and array sizes. The same interpreter evaluates row rules and page access rules on the server.

The browser is untrusted

Client workflows and bindings can be read and changed by visitors, so they never hold authority. Page access is enforced on the server, client queries of gated pages pass the same gate, and writes go through server workflows and row rules. In rules, an anonymous user has id: NaN so ownership checks never match ownerless rows.

Outbound requests

Integrations reach only their declared hosts. Server fetches require HTTPS, resolve hostnames over DNS-over-HTTPS and block private, loopback and link-local answers (redirects re-checked), and cap time and response size. runJs runs in a Worker Loader isolate with no bindings and no secrets.

Styles and HTML

Style values that could break out of a rule are rejected; property names are validated. The renderer escapes text and sanitizes URLs. Rich text is stored as structured JSON, never raw HTML. Custom site code runs only on published sites, never in the editor.

Abuse protection

Forms use Turnstile, a honeypot and per-IP and per-form limits, and store IPs hashed. Public endpoints, client queries, login and sign-up use Cloudflare rate limiting.