Security model
Who is trusted, what is not, and what you must add around PDF Server to run it safely.
PDF Server executes templated HTML in a real browser to produce PDFs. That makes the browser the security-critical component and the request data the primary untrusted input. This page defines the trust boundaries; the specific issues and fixes are in Proved issues and Possible issues.
Trust boundaries
| Actor / input | Trust | Rationale |
|---|---|---|
| Template author | Trusted | You write the templates, schemas, compositions (composition.js/jq), and remote-request templates, and you build the image. Author-supplied code is trusted. |
| Render-request data | Often untrusted | In many deployments the JSON body carries end-user input (a customer name/address on an invoice). Treat it as attacker-controlled unless you know otherwise. |
| The headless browser | Weak boundary | It executes whatever HTML/CSS/JS the render produces. It runs with --no-sandbox, so a renderer compromise lands as the container user. |
| Operator | Responsible | The service ships no auth, egress control, or browser sandbox — you provide them. |
Two common deployment shapes
- Untrusted data (e.g. public-facing invoices): the request body contains end-user input. All data-driven issues below are in scope. Harden accordingly.
- Internal data only (e.g. reports from your own systems): the body is trusted. Data-driven issues (XSS-into-PDF, URL SSRF from data) are largely not reachable, but network exposure and DoS considerations still apply.
Knowing which shape you are in tells you which issues to prioritise — each issue in the proved and possible lists is tagged with when it is reachable.
What the service does not provide
By design, PDF Server ships no:
- authentication or authorization on any endpoint;
- request body-size limit or HTTP read/write timeouts;
- outbound network (egress) restriction;
- browser OS sandbox (it runs
--no-sandbox).
Safety therefore depends on operator-side controls. See the hardening checklist.
Operator responsibilities (summary)
- Put an authenticating reverse proxy in front of the service; set body-size and timeout limits there.
- Apply an egress network policy blocking private and link-local ranges (e.g.
169.254.169.254, RFC-1918). - Run the container sandboxed (seccomp, and ideally user namespaces / gVisor) to compensate for
--no-sandbox, with CPU/memory limits. - Never feed untrusted data to raw-HTML sinks (
{{{triple}}}, themarkdown/embed_*helpers) or into URL/src/hrefpositions without validation. - Do not build remote-template requests from untrusted data.
Reporting
Please report security issues privately, not in a public issue. Open a confidential issue on the project’s GitLab (tick “This issue is confidential”) so the report stays visible only to the maintainers until a fix is available.