Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ It's a fork of the original CheetahTemplate library.
Python 2.7 or 3.6+ is required.


Templates are code
==================

Cheetah compiles a template into a Python module and runs it. Render
only templates you trust, never one built from user input; that is
remote code execution. There is no sandbox. See
https://cheetahtemplate.org/users_guide/security.html


Where is CheetahTemplate3
=========================

Expand Down
4 changes: 4 additions & 0 deletions docs/news.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ News
Development (master)
--------------------

- Docs: Added a chapter on security to the User's Guide. Templates
are code; rendering a template built from user input is remote
code execution, and no compiler setting prevents it.

- Dropped support for Python 3.4 and 3.5.

3.4.0.post5 (2025-11-29)
Expand Down
1 change: 1 addition & 0 deletions docs/users_guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Cheetah User's Guide
flowControl.rst
errorHandling.rst
parserInstructions.rst
security.rst

tipsAndTricks.rst
webware.rst
Expand Down
61 changes: 61 additions & 0 deletions docs/users_guide/security.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Security
========


A template is code
------------------


Cheetah compiles a template into a Python module and then runs it.
A placeholder is a Python expression, so a template can do anything
Python can do:

::

>>> from Cheetah.Template import Template
>>> print(Template('$__import__("os").popen("id").read()'))
uid=1000(user) gid=1000(user) groups=1000(user)

Template definitions are source code and need the same trust as the
rest of your program. Do not compile or render a template whose text
comes from a user, an upload, a request parameter or any other place
you do not control. Doing so is remote code execution.


Where user input belongs
------------------------


Pass user input to the template instead of into it:

::

# Wrong. The user writes the program.
print(Template(user_input))

# Right. The user fills a placeholder.
print(Template('Hello $name', searchList=[{'name': user_input}]))

Values in the searchList are looked up and written out, never
compiled. They still reach the output verbatim, so filter them for
the output format you generate; see the ``#filter`` directive and the
WebSafe filter for HTML.


There is no sandbox
-------------------


Compiler settings restrict the template language, not what a template
is allowed to do. The example above runs unchanged with
``useNameMapper=False`` and with every directive listed in
``disabledDirectives``, because none of that touches the placeholder
expression. Treat these settings as a way to keep templates simple,
not as a security boundary.

Cheetah does not offer a safe mode. Restricting Python expressions to
a safe subset inside the same interpreter has a long history of
escapes. If you have to render
templates you do not control, isolate the whole process: a separate
user account, a container, seccomp, or a jail, with the limits set
outside of Python.