Security

Security model

Morphis handles untrusted LLM output. This page documents exactly how we keep your application safe.

1 · Threat model

LLMs produce markup. Markup goes into web apps. The two together mean prompt injection and HTML injection are the primary classes of attack Morphis defends against:

  • Prompt injection — A hostile prompt tries to make the model produce unsafe markup.
  • HTML injection — Generated content contains scripts, event handlers, or dangerous URLs.
  • Style leakage — Scoped CSS escapes into the host application's design system.
  • Data exfiltration — Generated content tries to read the parent page's cookies or DOM.

2 · Defense in depth

Morphis applies four independent layers. Any one of them stopping an attack is enough; together they form a chain that's very hard to bypass.

Layer 1 — LLM behavioral constraints

The system prompt forbids script, onclick, onerror,javascript: URIs, and any event-handler attributes. It caps output to 4,096 tokens and requires strict JSON.

Layer 2 — Sanitization

The backend passes the model output through a bleach + BeautifulSoup AST walker that removes scripts, event handlers, hostile CSS, javascript: URLs, and data:text/html links. CSS url() values are validated against an explicit allowlist — only data:image/* values survive.

If the sanitized output is empty, the API fails loudly — no partial payload is ever served.

Layer 3 — Scoped CSS

All generated styles are wrapped under .morphis-root, the rendered component's outer wrapper class. Your page's button, input, and global styles cannot collide with generated components.

Layer 4 — Iframe sandbox

The SDK mounts generated content inside sandbox="allow-scripts" iframes with srcdoc. No top-level navigation, no form submission to your origin, no access to your DOM, cookies, or localStorage. Communication happens only via scoped postMessage.

3 · API key hygiene

  • Keys are hashed at rest with SHA-256 — only the hash exists in our database.
  • Shown to you once at creation; after that, it's permanently unreadable.
  • Revocation in the dashboard is instantaneous — our runtime reads from the database on every call.
  • Each key is scoped to a tenant, so one leaked key cannot affect another customer's quota.

4 · In transit

  • All traffic uses HTTPS with TLS 1.3 (forced via ALB redirect).
  • WebSocket connections are not used. The API is stateless REST with a short timeout.
  • Password hashing uses PBKDF2-SHA256 (100,000 iterations) with per-user salting.

5 · Responsible disclosure

Found a security issue? We take it seriously. Email ibrahim@getmorphis.com with:

  • The vulnerability class (XSS, SSRF, injection, auth bypass, etc.)
  • Steps or payload that prove it
  • The affected endpoint or component

We respond within 48 hours. We do not currently run a formal bug bounty — but we credit researchers in a Hall of Fame on this page.