Possible security issues
Reachability legend — U = untrusted data · I = internal data · N = network-exposed. See Proved issues for confirmed findings and the security model for context.
SSRF / resource loading from untrusted URLs in markup — U (high impact)
Any template that places untrusted data into an <img src>, <iframe>,
<link>, <script>, or fetch() URL lets the browser fetch attacker-chosen
targets (internal services, cloud metadata). Auto-escaping prevents tag
break-out but not a malicious URL value. file:// subresource loads are
normally blocked by the browser's default policy (no
--allow-file-access-from-files is set), so local-file read is likely mitigated
by the browser rather than by application code.
- Verify: whether any deployed template puts untrusted data in a URL position; current browser behavior for the pinned image.
- Mitigate: an egress network policy blocking private/link-local ranges; validate/allowlist URL values in templates.
JavaScript composition planner has no interrupt/timeout — U (DoS, author-trusted)
The JS planner (composition.js) runs in goja with no execution deadline and a
shared mutex. A data-driven infinite loop in the (trusted) planner would hang the
request and serialize other renders of that composition. goja has no filesystem
or network access, so impact is limited to CPU/hang.
- Verify: whether any timeout wraps the planner call.
- Mitigate: set a runtime interrupt/deadline around
buildPlan.
Log injection via request fields — N (low, likely mitigated)
The request-ID query parameter and request path/query are logged. The default text formatter quotes special characters (newlines are escaped), which largely prevents forged log lines; JSON format is safe.
- Verify: the configured formatter in production.
- Mitigate: constrain/validate the
request_idparameter; use JSON logs.
Internal server exposes any template's assets to the rendering page — U (low)
The internal render server serves /templates/<name>/assets/* for any template
name. Path traversal outside a template's assets/ is blocked, but a rendering
page could read other templates' (non-secret by design) asset files.
- Mitigate: scope asset access to the current render if templates ship sensitive assets (they should not).
embed_* path taken from data — U (low)
If a template passes untrusted data as the path to embed_text/embed_base64,
an attacker could read arbitrary files within that template's assets/
directory (traversal outside is blocked).
- Mitigate: never pass untrusted data as an embed path.