CVE-2023-6395 (published 2024-01-16T15:15Z)

The Mock software contains a vulnerability wherein an attacker could potentially exploit privilege escalation, enabling the execution of arbitrary code with root user privileges. This weakness stems from the absence of proper sandboxing during the expansion and execution of Jinja2 templates, which may be included in certain configuration parameters. While the Mock documentation advises treating users added to the mock group as privileged, certain build systems invoking mock on behalf of users might inadvertently permit less privileged users to define configuration tags. These tags could then be passed as parameters to mock during execution, potentially leading to the utilization of Jinja2 templates for remote privilege escalation and the execution of arbitrary code as the root user on the build server.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/xsuchy/templated-dictionary
commit_details: repo_url: https://github.com/xsuchy/templated-dictionary
author: Pavel Raiskup
author_date: 2023-12-11 09:28:17+01:00
msg: Make the TemplatedDictionary objects picklable

The jinja2 SandboxedEnvironment objects are not guaranteed to be
pickle-serializable (even though they practically are).  So let's rather
store the environment elsewhere than in the TemplatedDictionary object
itself to keep it serializable.

Nb. TemplatedDictionary is just a wrapper around dict, which is quite
commonly subject of (de)serialization (e.g. Mock, the main user of
templated-dictionary library does that through the
concurrent.futures.ProcessPoolExecutor logic).

It would be disadvantageous to introduce additional internal arguments
into the object itself (considering we already have the __jinja_expand
internal).

Having a per-application shared environment is kind of expected anyway
(and even more optimal):

    https://jinja.palletsprojects.com/en/3.0.x/api/#basics

Note that this fix is mostly needed for the RHEL 8 environment with
jinja2 v2.10.1; newer versions made the environments (namely the
included filters) picklable: https://github.com/pallets/jinja/pull/1613
repository: repo_url: https://github.com/xsuchy/templated-dictionary
repo_name: xsuchy/templated-dictionary
description: Python dictionary with Jinja2 expansion
repo_language: Python
owner: xsuchy
file_changes: filename: __init__.py
change_type: ModificationType.MODIFY
diff: @@ -4,6 +4,7 @@
 from collections.abc import MutableMapping
 from jinja2 import sandbox
 
+SANDBOX = sandbox.SandboxedEnvironment(keep_trailing_newline=True)
 
 # pylint: disable=no-member,unsupported-assignment-operation
 class TemplatedDictionary(MutableMapping):
@@ -19,8 +20,6 @@ class TemplatedDictionary(MutableMapping):
         '''
         self.__dict__.update(*args, **kwargs)
 
-        self.sandbox = sandbox.SandboxedEnvironment(keep_trailing_newline=True)
-
         self._aliases = {}
         if alias_spec:
             for aliased_to, aliases in alias_spec.items():
@@ -82,7 +81,7 @@ class TemplatedDictionary(MutableMapping):
         orig = last = value
         max_recursion = self.__dict__.get('jinja_max_recursion', 5)
         for _ in range(max_recursion):
-            value = _to_native(self.sandbox.from_string(value).render(self.__dict__, func=lambda:None))
+            value = _to_native(SANDBOX.from_string(value).render(self.__dict__, func=lambda:None))
             if value == last:
                 return value
             last = value

programming_language: Python
repo_url: https://github.com/xsuchy/templated-dictionary
commit_details: repo_url: https://github.com/xsuchy/templated-dictionary
author: Pavel Raiskup
author_date: 2023-11-30 10:26:01+01:00
msg: Use a sandboxed jinja2 environment

The task of templated_dictionary object is pretty simple, it just
expands precisely defined set of templates (dictionary attributes).
Having a full power of Python interpreter in templates doesn't seem to
make any sense.  So let's make the library safer.
repository: repo_url: https://github.com/xsuchy/templated-dictionary
repo_name: xsuchy/templated-dictionary
description: Python dictionary with Jinja2 expansion
repo_language: Python
owner: xsuchy
file_changes: filename: __init__.py
change_type: ModificationType.MODIFY
diff: @@ -2,7 +2,7 @@
 # vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0:
 
 from collections.abc import MutableMapping
-import jinja2
+from jinja2 import sandbox
 
 
 # pylint: disable=no-member,unsupported-assignment-operation
@@ -19,6 +19,8 @@ class TemplatedDictionary(MutableMapping):
         '''
         self.__dict__.update(*args, **kwargs)
 
+        self.sandbox = sandbox.SandboxedEnvironment(keep_trailing_newline=True)
+
         self._aliases = {}
         if alias_spec:
             for aliased_to, aliases in alias_spec.items():
@@ -80,8 +82,7 @@ class TemplatedDictionary(MutableMapping):
         orig = last = value
         max_recursion = self.__dict__.get('jinja_max_recursion', 5)
         for _ in range(max_recursion):
-            template = jinja2.Template(value, keep_trailing_newline=True)
-            value = _to_native(template.render(self.__dict__))
+            value = _to_native(self.sandbox.from_string(value).render(self.__dict__, func=lambda:None))
             if value == last:
                 return value
             last = value

programming_language: Python