Trust Center
Last updated: 2 August 2026
Every claim on this page is measured from the source code and re-checked by a build gate. Where the evidence does not exist yet, this page says so rather than staying quiet.
Memory safety
Every line of code that reads untrusted PDF bytes is memory-safe Rust. There is no C or C++ in the parsing path, and none in its dependency closure either. This is not a roadmap commitment; it is the state of the code today, and the compiler is what enforces it.
- 19 of 30 Rust crates compile under #![forbid(unsafe_code)], a setting no submodule can re-open.
- 0 unsafe operations are reachable across the 21 PDF engine crates, in every build configuration we produce.
- 71 crates in the parser dependency closure, of which 0 are linked C or C++ libraries.
- 0 unsafe operations across 3 browser (WebAssembly) packages.
- 11 fuzz targets run continuously against the parsing path, each with a seed corpus.
The workspace contains 21 unsafe operations in total, every one of them outside the PDF path: Windows credential-store and TPM calls, a kiosk keyboard hook, and two test helpers. Each is listed with its justification in the full statement.
The PDFium boundary
PDFium is C++, and we do not hide that. It produces raster pixels for visual evidence and nothing else. Preflight verdicts, the rule registry and conformance decisions come out of our own Rust core without ever passing through it. PDFium cannot approve or reject a file.
- Runs as a separate operating system process; it is never linked in as a library.
- No network access, non-root user, read-only root filesystem, all capabilities dropped.
- One page at a time, with CPU, memory, process and temporary storage limits enforced by the kernel.
- JavaScript (V8) and XFA are compiled out, removing the largest part of PDFium historical vulnerability surface.
- Isolation receipts are signed by an independent supervisor; the worker cannot attest to its own isolation.
What is not yet proven: the reproducible PDFium build that would supply the pinned binary digest has not been produced. Our supply-chain validator therefore rejects the build manifest currently in the repository, and the render backend is not production-eligible. The gate is fail-closed, so missing evidence means the path does not run rather than running unverified. The memory-safety claim above is independent of this, because the parsing path never reaches PDFium.
What we claim, and what we do not
A preflight report is diagnostic evidence. It measures a file and tells you what is in it; it does not modify the file, and it is not a production proof. Keeping that line visible is the whole point of this section.
We claim
- We measure your PDF and report what we found, naming the rule and threshold behind every finding.
- We never alter your file: no colour conversion, no flattening, no font substitution, no trapping.
- Every finding carries the engine version and the rule registry version that produced it.
- The parsing path is memory-safe Rust, and a build gate re-checks that claim on every change.
We do not claim
- A diagnostic report is not a certified proof and not a print-readiness guarantee.
- Rendered pixels are not RIP-equivalent and carry no separation authority.
- An SBOM lists components; it says nothing about known vulnerabilities.
- Nothing here asserts the absence of bugs, only that one whole class of them is excluded by construction.
Software Bill of Materials
CycloneDX 1.6, generated from the committed lockfiles. The repository stores the digest of each BOM rather than the BOM itself, because a BOM is a pure function of a lockfile that is already committed. CI verifies on every run that the digest still matches those lockfiles.
| BOM | Components | SHA-256 |
|---|---|---|
| sbom-rust.cdx.json | 871 | f9e3f4531eda6cc2… |
| sbom-npm.cdx.json | 2452 | d944df1f6a65a671… |
The full BOMs are published as release artefacts. To request them, or a copy for a procurement file, write to security@nowtoprint.com.
Coordinated vulnerability disclosure
Report through the repository security advisory channel or by email. We acknowledge within 3 working days and give a first assessment within 10 working days. These are upper bounds set by the size of the team, not targets. We coordinate disclosure timing with you, and if no fix has shipped within 90 days the decision to publish is yours.
Under the EU Cyber Resilience Act (2024/2847), from 11 September 2026 an actively exploited vulnerability or a severe incident must reach ENISA and the relevant CSIRT as an early warning within 24 hours and as a notification within 72 hours. That obligation runs to the regulator, not to the reporter: it is fed by the same process, but it is not the same promise.
Security contact: security@nowtoprint.com
Evidence
The claims above are generated from the files below. The repository is private, so they are listed by path: an auditor can ask for any of them by name during a procurement review.
- docs/security/MEMORY_SAFETY_STATEMENT_2026.md
- docs/security/MEMORY_SAFETY_STATEMENT_2026_TR.md
- docs/api/generated/sbom-manifest.v1.json
- docs/api/generated/repo-facts.v1.json
- deploy/pdf-workers/pdf-worker-isolation-policy.v1.json
- scripts/ci/memory-safety-claim-check.mjs
- SECURITY.md