diff --git a/docs/canvases-feature.html b/docs/canvases-feature.html index 5ca3aae4d..5334a0eb3 100644 --- a/docs/canvases-feature.html +++ b/docs/canvases-feature.html @@ -214,6 +214,7 @@
  • File map
  • Try it locally
  • Roadmap
  • +
  • Why no html canvas type?
  • Deliberate non-goals
  • @@ -623,7 +624,45 @@ EOF -

    10. Deliberate non-goals

    +

    10. Why no html canvas type?

    +

    The most-asked design question — answered honestly here so reviewers don't have to ask.

    +

    Two reasons, both load-bearing.

    + +

    Trust hierarchy inversion

    +

    Agents are the lowest-trust surface in the system. They emit content on every poll cycle, and large parts of that content come from LLMs that can be prompt-injected. If an agent ingests a malicious URL, summarizes a poisoned document, or just hits a jailbreak, its next "render this nice summary" call could include attacker-controlled HTML. Putting that HTML into the same-origin dashboard means the attacker now has:

    + +

    That's the same blast radius v0.4 renderer plugins have — but renderer plugins clear npm install review once. An agent emits a fresh canvas every poll. The trust gap is enormous.

    + +

    HTML sanitization is a leaky abstraction

    +

    DOMPurify, sanitize-html, etc. are honest attempts but every year ships new bypasses — <svg> foreign objects, <math> payloads, mutation-XSS via clipboard, CSS exfiltration via attr(). A sanitizer-based HTML canvas is a 90% solution that fails open on the 10%, and the 10% is "execute arbitrary JS in your supervisor". Even GitHub, GitLab, and Slack treat HTML rendering as a multi-quarter security investment, not a feature you slot in next to markdown.

    + +

    What the existing types cover

    + + + + + + + + + + +
    You want to renderUse
    Formatted text with bold / italic / headings / code / listsmarkdown (the v0.1 parser handles all of this safely — no HTML pass-through)
    Code changesdiff
    Structured rowstable
    Metric cardsstats
    Custom UI (flame graph, Gantt, network diagram)canvas-renderer plugin (v0.4)
    Genuinely arbitrary, untrusted markupSandboxed iframe canvas — credible v0.5+ option, deferred
    + +

    The legitimate "I need raw HTML" path — sandboxed iframe

    +

    An iframe with sandbox="allow-scripts" (no allow-same-origin) runs in a null origin — it can't reach your auth tokens or call APIs. Add a postMessage protocol for size negotiation and limited event-out, document the trust trade-off explicitly, and you've got a real HTML surface that's safe by construction.

    +

    But — per codex's pass-13 advice — half-baked iframe support is worse than no sandbox. Sandbox protocols have to be designed end-to-end (CSP headers, postMessage validation, focus management, accessibility, viewport sizing) before they ship. v0.4 renderer plugins is the bigger unlock; the iframe canvas comes after, only if a real use case shows up.

    + +
    + Bottom line — not because we couldn't, but because direct HTML inverts the trust hierarchy (agents shouldn't be able to JS-execute in the supervisor) and sanitizers don't fix that. The plugin path covers most "I need a custom widget" cases at v0.4. Sandboxed iframe is the answer for genuine arbitrary HTML when we're ready to design the protocol properly. +
    + +

    11. Deliberate non-goals