Proved security issues
Verified in the source. Each issue is tagged with when it is reachable so you can prioritise for your deployment.
Reachability legend — U = reachable when render data is untrusted · I = reachable even with internal-only data · N = reachable when network-exposed without an auth proxy. Not every issue applies to every deployment; see the security model.
These are findings for the maintainers and operators to prioritise. Several are latent in a given deployment (e.g. they require untrusted data, which some installations never pass). They are documented honestly rather than assumed exploitable everywhere.
Critical
SSRF + header injection via remote templates — U
A remote template renders a raw HTTP request from template data and executes it with an HTTP client that has no timeout and no SSRF guard. If any part of the URL/host/headers comes from untrusted data, a caller can make the server fetch internal endpoints (e.g. cloud metadata at 169.254.169.254), and CR/LF in a value can inject headers or override Host.
- Reachable: only if you deploy a remote template whose request is built from untrusted data. Remote templates fed only trusted/fixed data are not affected.
- Fix: parse and allowlist scheme + host; block private/link-local ranges via a custom dialer; add a client timeout, header-size and response-size caps; reject CR/LF in interpolated values. Consider gating the remote loader behind an explicit opt-in flag.
High
Browser runs with --no-sandbox — U I
The default browser args include --no-sandbox. A renderer exploit (or a chained XSS, below) then executes as the container user.
- Reachable: the sandbox is off regardless of data trust; exploitation requires a browser bug or an XSS sink.
- Fix / mitigation: run the container under seccomp + user namespaces (or gVisor), with an egress policy, so an escape is contained. Document
--no-sandboxas requiring an external sandbox.
No authentication on any endpoint — N
No route requires auth. Anyone who can reach the port can render any template, drive the remote-template fetch, and consume resources.
- Fix: deploy behind an authenticating reverse proxy (or add optional API-key/mTLS middleware). See the hardening checklist.
XSS-into-PDF via raw-HTML sinks — U
The markdown helper returns unescaped HTML and does not strip embedded HTML; embed_text and {{{triple}}} also emit raw HTML. Untrusted data reaching these executes as active content in the (unsandboxed) browser.
- Reachable: only where a template passes untrusted data into one of these sinks. Auto-escaping (
{{ }}, Gohtml/template) otherwise prevents injection. - Fix: sanitize untrusted markdown (e.g. bluemonday) or enable
SkipHTML; document that these sinks must never receive untrusted data.
Medium
Predictable internal document IDs — U
The internal render server keys documents by an ID derived from a fixed-seed PRNG, so IDs are deterministic across restarts. Combined with any in-page JS (same-origin to the internal server), an attacker could predict IDs and read other renders’ HTML.
- Fix: seed document IDs from
crypto/rand.
DoS: no body limit, no server timeouts, single-slot default, hanging remote fetch, unbounded composition fan-out — N (U for the last two)
There is no request body-size limit and no HTTP read/write timeouts; the default pool is a single browser (so one slow render serializes all others); the remote-template client has no timeout; and composition planners are data-driven with no depth/breadth cap.
- Fix: add a body-size limit and read/write/idle timeouts (at the proxy today, in-process ideally); raise the pool size; add a remote-fetch timeout; cap composition recursion/task count.
Composite sub-template schema bypass — U
Only the composition’s own schema.json is validated; each child template’s schema is not re-validated when reached through a composition, so data hardening a child relies on can be skipped.
- Fix: validate each child task’s data against its template’s validator before rendering. Until then, validate at the composition boundary.
Priority order
- Remote-template SSRF (if remote templates use untrusted data).
- Sandbox + auth + egress (deploy-time controls).
- Raw-HTML XSS sinks (if untrusted data reaches them).
- Predictable document IDs.
- DoS controls (body limit, timeouts, pool size, fetch timeout, composition caps).
- Composite validation bypass.
See Possible issues for suspected items needing further verification, and the hardening checklist for the operator controls that mitigate several of the above at once.