Safeguard
Application Security•

ASVS 5.0 V1.2.8: Lock Down LaTeX Processors

ASVS V1.2.8 requires LaTeX processors without shell escape and a command allowlist. See the flags, a safe wrapper and the tests that prove it works.

Safeguard Security Team
2 min read

ASVS 5.0 V1.2.8 (Level 2) requires that any LaTeX processor your application runs is configured securely, which means no --shell-escape, and that an allowlist of commands is enforced so users cannot inject dangerous LaTeX. It matters for apps that turn user text into PDFs, such as invoices, reports and certificates.

Why it matters

LaTeX is a programming language. With shell escape on, a document can run operating system commands. Even without it, commands like \input and \include can read local files, and \write18 style features can write them. A user who controls part of the source can read /etc/passwd into the PDF.

How to implement it

Run the processor with restrictions and treat user text as data, not markup.

import subprocess, tempfile, pathlib

def render(tex_source: str) -> bytes:
    with tempfile.TemporaryDirectory() as d:
        src = pathlib.Path(d, "doc.tex")
        src.write_text(tex_source, encoding="utf-8")
        subprocess.run(
            ["pdflatex", "-no-shell-escape", "-interaction=nonstopmode",
             "-halt-on-error", "-output-directory", d, str(src)],
            cwd=d, timeout=20, check=True, capture_output=True,
            env={"openin_any": "p", "openout_any": "p", "PATH": "/usr/bin"},
        )
        return pathlib.Path(d, "doc.pdf").read_bytes()

The environment values set openin_any and openout_any to paranoid mode, which limits file access. Better still, escape user text so it can never form a command: replace the backslash, braces, $, &, #, _, %, ^ and ~ with their safe forms before placing it into a template you control. Run the process in a container with no network and a read only filesystem apart from the working folder.

How to test it

Put \input{/etc/passwd} and \immediate\write18{id} in a user field. The PDF must contain the literal text or the build must fail. Check the command line for -no-shell-escape or -shell-restricted and confirm that your TeX configuration does not enable shell_escape = t.

Common mistakes

  • Enabling shell escape for one package and never turning it off.
  • Passing user supplied source files rather than filling a fixed template.
  • Running the compiler as the application account with full file access.

Quick check

Is disabling shell escape enough?

No. File read commands still exist, so also escape user text, restrict file access and sandbox the process.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.