Fixed #33986 -- Hardened binary lookup in template commands.
Made template commands look up formatters before writing files. This makes sure files included in the template are not identified as executable formatter commands, even in case the template is rendered into the system path (as might easily happen on Windows, where the current directory is on the system path by default). While at it, Warned about trusting custom templates for startapp/startproject. Thanks Trung Pham of Viettel Cyber Security for reporting the issue, Django Security Team for discussions, and Adam Johnson and Carlton Gibson for reviews.
This commit is contained in:
parent
19e838daa8
commit
42cd8c390d
|
@ -11,7 +11,11 @@ from urllib.request import build_opener
|
|||
import django
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management.utils import handle_extensions, run_formatters
|
||||
from django.core.management.utils import (
|
||||
find_formatters,
|
||||
handle_extensions,
|
||||
run_formatters,
|
||||
)
|
||||
from django.template import Context, Engine
|
||||
from django.utils import archive
|
||||
from django.utils.http import parse_header_parameters
|
||||
|
@ -107,6 +111,10 @@ class TemplateCommand(BaseCommand):
|
|||
"exist, please create it first." % top_dir
|
||||
)
|
||||
|
||||
# Find formatters, which are external executables, before input
|
||||
# from the templates can sneak into the path.
|
||||
formatter_paths = find_formatters()
|
||||
|
||||
extensions = tuple(handle_extensions(options["extensions"]))
|
||||
extra_files = []
|
||||
excluded_directories = [".git", "__pycache__"]
|
||||
|
@ -224,7 +232,7 @@ class TemplateCommand(BaseCommand):
|
|||
else:
|
||||
shutil.rmtree(path_to_remove)
|
||||
|
||||
run_formatters(self.written_files)
|
||||
run_formatters(self.written_files, **formatter_paths)
|
||||
|
||||
def handle_template(self, template, subdir):
|
||||
"""
|
||||
|
|
|
@ -157,11 +157,18 @@ def is_ignored_path(path, ignore_patterns):
|
|||
return any(ignore(pattern) for pattern in normalize_path_patterns(ignore_patterns))
|
||||
|
||||
|
||||
def run_formatters(written_files):
|
||||
def find_formatters():
|
||||
return {"black_path": shutil.which("black")}
|
||||
|
||||
|
||||
def run_formatters(written_files, black_path=(sentinel := object())):
|
||||
"""
|
||||
Run the black formatter on the specified files.
|
||||
"""
|
||||
if black_path := shutil.which("black"):
|
||||
# Use a sentinel rather than None, as which() returns None when not found.
|
||||
if black_path is sentinel:
|
||||
black_path = shutil.which("black")
|
||||
if black_path:
|
||||
subprocess.run(
|
||||
[black_path, "--fast", "--", *written_files],
|
||||
capture_output=True,
|
||||
|
|
|
@ -1362,6 +1362,19 @@ files is:
|
|||
byte-compile invalid ``*.py`` files, template files ending with ``.py-tpl``
|
||||
will be renamed to ``.py``.
|
||||
|
||||
.. _trusted_code_warning:
|
||||
|
||||
.. warning::
|
||||
|
||||
The contents of custom app (or project) templates should always be
|
||||
audited before use: Such templates define code that will become
|
||||
part of your project, and this means that such code will be trusted
|
||||
as much as any app you install, or code you write yourself.
|
||||
Further, even rendering the templates is, effectively, executing
|
||||
code that was provided as input to the management command. The
|
||||
Django template language may provide wide access into the system,
|
||||
so make sure any custom template you use is worthy of your trust.
|
||||
|
||||
``startproject``
|
||||
----------------
|
||||
|
||||
|
@ -1418,8 +1431,9 @@ The :class:`template context <django.template.Context>` used is:
|
|||
- ``docs_version`` -- the version of the documentation: ``'dev'`` or ``'1.x'``
|
||||
- ``django_version`` -- the version of Django, e.g. ``'2.0.3'``
|
||||
|
||||
Please also see the :ref:`rendering warning <render_warning>` as mentioned
|
||||
for :djadmin:`startapp`.
|
||||
Please also see the :ref:`rendering warning <render_warning>` and
|
||||
:ref:`trusted code warning <trusted_code_warning>` as mentioned for
|
||||
:djadmin:`startapp`.
|
||||
|
||||
``test``
|
||||
--------
|
||||
|
|
Loading…
Reference in New Issue