Unrestricted shell escape for package automation versus restricted mode in CI pipelines
0 reputation · 20 Dec 2023, 06:27 UTC
0 reputation · 20 Dec 2023, 06:27 UTC
Modern LaTeX workflows often require unrestricted shell escape (–shell-escape) to support packages such as minted, epstopdf-auto, or latexmk’s automatic dependency resolution. At the same time, continuous-integration pipelines and shared build servers must limit the attack surface of untrusted source files.
TeX Live and MiKTeX ship with a restricted whitelist that permits only a small set of known-safe commands. The whitelist differs between distributions and can change across releases, so a project that compiles locally may fail on a CI runner without an explicit opt-in. Conversely, granting full shell escape globally defeats the principle of least privilege and exposes the host to arbitrary command execution.
texmf.cnf snippet or latexmkrc) that CI systems can honor without manual --shell-escape flags?\write18 call while still allowing the required external tools?31275 reputation · 20 Dec 2023, 13:02 UTC
There is no distribution-agnostic, per-project mechanism (such as a texmf.cnf snippet or latexmkrc) that allows a TeX engine to automatically opt-in to shell escape permissions. The restricted whitelist is a global installation setting. To enable the external calls required by packages like minted or epstopdf-auto, the --shell-escape flag must be passed explicitly to the engine during the build process.
TeX Live and MiKTeX maintain separate whitelists of "safe" commands (viewable via kpsewhich --var-value=shell_escape_commands in TeX Live). Because these lists vary by distribution and version, a project relying on restricted mode may compile locally but fail in CI. Since tools like pygmentize (used by minted) are not on these whitelists, unrestricted shell escape is effectively mandatory for these workflows.
When --shell-escape is required, the security boundary must shift from the TeX engine to the environment. For workflows that cannot migrate to LuaTeX, the following containment strategies are recommended:
\write18 call from persisting changes to the source or accessing the host filesystem.HOME directory./usr/bin/python3 for minted) to be executed via execve.To identify exactly which external binaries your project requires before locking down a sandbox, run the build with strace in a controlled environment:
strace -f latexmk -pdf -shell-escape document.tex 2>&1 | grep -E 'execve|openat'
This will enumerate the binaries being called, allowing you to create a precise whitelist for your seccomp profile or container permissions.
To refine the recommendation: Are you using a pre-baked TeX Live Docker image, or are you installing the distribution dynamically on a shared runner (e.g., GitHub-hosted runners)?
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.