Jinja has a sandbox breakout through indirect reference to format method
Description
Jinja is an extensible templating engine. Prior to 3.1.5, An oversight in how the Jinja sandboxed environment detects calls to str.format allows an attacker that controls the content of a template to execute arbitrary Python code. To exploit the vulnerability, an attacker needs to control the content of a template. Whether that is the case depends on the type of application using Jinja. This vulnerability impacts users of applications which execute untrusted templates. Jinja's sandbox does catch calls to str.format and ensures they don't escape the sandbox. However, it's possible to store a reference to a malicious string's format method, then pass that to a filter that calls it. No such filters are built-in to Jinja, but could be present through custom filters in an application. After the fix, such indirect calls are also handled by the sandbox. This vulnerability is fixed in 3.1.5.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
An attacker controlling template content can exploit an oversight in Jinja's sandbox to execute arbitrary Python code via indirect str.format calls, fixed in 3.1.5.
Overview
CVE-2024-56326 is a sandbox escape vulnerability in Jinja, an extensible Python templating engine, affecting versions prior to 3.1.5. The core issue is an oversight in how the sandboxed environment detects calls to str.format [1]. Although the sandbox correctly intercepts direct calls to str.format, an attacker can bypass this restriction by storing a reference to a malicious string's format method and then passing that reference to a filter that invokes it [1]. No built-in Jinja filters perform such a call, but the vulnerability becomes exploitable if the application uses any custom filter that calls its argument [1].
Exploitation
To exploit this vulnerability, an attacker must control the content of a template [1]. This condition is met in applications that execute untrusted templates, for example, those that allow user-submitted templates or template fragments [1]. The attack does not require any particular network position beyond the ability to provide template content, and no prior authentication is specified as a barrier [1]. The exploitation chain depends on the presence of a custom filter that calls the passed object, which then invokes the stored format method, leading to arbitrary code execution [1].
Impact
Successful exploitation allows an attacker to execute arbitrary Python code within the context of the Jinja environment [1]. This can lead to full compromise of the application server, including data theft, modification, or denial of service, depending on the privileges of the running process [1].
Mitigation
The vulnerability is fixed in Jinja version 3.1.5 [1]. Users should upgrade immediately. Applications that cannot upgrade should avoid executing untrusted templates or review custom filters to ensure they do not inadvertently call methods obtained from template-provided objects [1].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
jinja2PyPI | < 3.1.5 | 3.1.5 |
Affected products
160- osv-coords158 versionspkg:apk/chainguard/airflowpkg:apk/chainguard/airflow-bitnami-compatpkg:apk/chainguard/airflow-compatpkg:apk/chainguard/ansible-operatorpkg:apk/chainguard/ansible-operator-compatpkg:apk/chainguard/apache-beam-python-3.11-sdkpkg:apk/chainguard/checkovpkg:apk/chainguard/dask-gatewaypkg:apk/chainguard/dask-gateway-serverpkg:apk/chainguard/emissarypkg:apk/chainguard/emissary-apiextpkg:apk/chainguard/emissary-oci-entrypointpkg:apk/chainguard/kservepkg:apk/chainguard/kserve-agentpkg:apk/chainguard/kserve-agent-compatpkg:apk/chainguard/kserve-managerpkg:apk/chainguard/kserve-manager-compatpkg:apk/chainguard/kserve-qpextpkg:apk/chainguard/kserve-qpext-compatpkg:apk/chainguard/kserve-routerpkg:apk/chainguard/kserve-router-compatpkg:apk/chainguard/kserve-storage-controllerpkg:apk/chainguard/kubeflow-jupyter-web-apppkg:apk/chainguard/kubeflow-pipelines-visualization-serverpkg:apk/chainguard/kubeflow-volumes-web-apppkg:apk/chainguard/localstackpkg:apk/chainguard/localstack-compatpkg:apk/chainguard/mlflowpkg:apk/chainguard/mlflow-bitnamipkg:apk/chainguard/mlflow-iamguarded-compatpkg:apk/chainguard/nemopkg:apk/chainguard/nvidia-apex-12.3pkg:apk/chainguard/nvidia-apex-12.3-wheelpkg:apk/chainguard/py3.10-ambassadorpkg:apk/chainguard/py3.10-jinja2pkg:apk/chainguard/py3.10-torchvision-cuda-11.8pkg:apk/chainguard/py3.10-torchvision-cuda-12.3pkg:apk/chainguard/py3.10-vllm-cuda-11.8pkg:apk/chainguard/py3.10-vllm-cuda-12.6pkg:apk/chainguard/py3.10-wheels-torchvision-cuda-11.8pkg:apk/chainguard/py3.10-wheels-torchvision-cuda-12.3pkg:apk/chainguard/py3.10-wheels-vllm-cuda-11.8pkg:apk/chainguard/py3.11-ambassadorpkg:apk/chainguard/py3.11-jinja2pkg:apk/chainguard/py3.11-torchaudio-cuda-12.3pkg:apk/chainguard/py3.11-torchvision-cuda-11.8pkg:apk/chainguard/py3.11-torchvision-cuda-12.3pkg:apk/chainguard/py3.11-wheels-torchaudio-cuda-12.3pkg:apk/chainguard/py3.11-wheels-torchvision-cuda-11.8pkg:apk/chainguard/py3.11-wheels-torchvision-cuda-12.3pkg:apk/chainguard/py3.12-ambassadorpkg:apk/chainguard/py3.12-jinja2pkg:apk/chainguard/py3.12-torchvision-cuda-12.3pkg:apk/chainguard/py3.12-wheels-torchvision-cuda-11.8pkg:apk/chainguard/py3.12-wheels-torchvision-cuda-12.3pkg:apk/chainguard/py3.13-ambassadorpkg:apk/chainguard/py3.13-jinja2pkg:apk/chainguard/py3.8-torchvision-cuda-11.8pkg:apk/chainguard/py3.8-wheels-torchvision-cuda-11.8pkg:apk/chainguard/py3.9-torchvision-cuda-11.8pkg:apk/chainguard/py3.9-torchvision-cuda-12.3pkg:apk/chainguard/py3.9-wheels-torchvision-cuda-11.8pkg:apk/chainguard/py3.9-wheels-torchvision-cuda-12.3pkg:apk/chainguard/py3-jinja2pkg:apk/chainguard/py3-supported-jinja2pkg:apk/chainguard/reflexpkg:apk/chainguard/supersetpkg:apk/chainguard/superset-cipkg:apk/chainguard/superset-entrypointpkg:apk/chainguard/superset-iamguarded-compatpkg:apk/wolfi/airflowpkg:apk/wolfi/airflow-bitnami-compatpkg:apk/wolfi/airflow-compatpkg:apk/wolfi/ansible-operatorpkg:apk/wolfi/ansible-operator-compatpkg:apk/wolfi/checkovpkg:apk/wolfi/dask-gatewaypkg:apk/wolfi/dask-gateway-serverpkg:apk/wolfi/emissarypkg:apk/wolfi/emissary-apiextpkg:apk/wolfi/emissary-oci-entrypointpkg:apk/wolfi/kservepkg:apk/wolfi/kserve-agentpkg:apk/wolfi/kserve-agent-compatpkg:apk/wolfi/kserve-managerpkg:apk/wolfi/kserve-manager-compatpkg:apk/wolfi/kserve-qpextpkg:apk/wolfi/kserve-qpext-compatpkg:apk/wolfi/kserve-routerpkg:apk/wolfi/kserve-router-compatpkg:apk/wolfi/kserve-storage-controllerpkg:apk/wolfi/kubeflow-jupyter-web-apppkg:apk/wolfi/kubeflow-pipelines-visualization-serverpkg:apk/wolfi/kubeflow-volumes-web-apppkg:apk/wolfi/mlflowpkg:apk/wolfi/mlflow-bitnamipkg:apk/wolfi/mlflow-iamguarded-compatpkg:apk/wolfi/py3.10-ambassadorpkg:apk/wolfi/py3.10-jinja2pkg:apk/wolfi/py3.11-ambassadorpkg:apk/wolfi/py3.11-jinja2pkg:apk/wolfi/py3.12-ambassadorpkg:apk/wolfi/py3.12-jinja2pkg:apk/wolfi/py3.13-ambassadorpkg:apk/wolfi/py3.13-jinja2pkg:apk/wolfi/py3-jinja2pkg:apk/wolfi/py3-supported-jinja2pkg:apk/wolfi/reflexpkg:apk/wolfi/supersetpkg:apk/wolfi/superset-cipkg:apk/wolfi/superset-entrypointpkg:apk/wolfi/superset-iamguarded-compatpkg:pypi/jinja2pkg:rpm/almalinux/fence-agents-commonpkg:rpm/almalinux/fence-agents-computepkg:rpm/almalinux/fence-agents-ibm-powervspkg:rpm/almalinux/fence-agents-ibm-vpcpkg:rpm/almalinux/fence-agents-kubevirtpkg:rpm/almalinux/fence-agents-virshpkg:rpm/almalinux/fence-virtpkg:rpm/almalinux/fence-virtdpkg:rpm/almalinux/fence-virtd-cpgpkg:rpm/almalinux/fence-virtd-libvirtpkg:rpm/almalinux/fence-virtd-multicastpkg:rpm/almalinux/fence-virtd-serialpkg:rpm/almalinux/fence-virtd-tcppkg:rpm/almalinux/python3-jinja2pkg:rpm/opensuse/oci-cli&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/python-Jinja2&distro=openSUSE%20Leap%2015.5pkg:rpm/opensuse/python-Jinja2&distro=openSUSE%20Leap%2015.6pkg:rpm/opensuse/python-Jinja2&distro=openSUSE%20Leap%20Micro%205.5pkg:rpm/rocky-linux/fence-agents?distro=rocky-linux-9&epoch=0pkg:rpm/suse/python-Jinja2&distro=SUSE%20Enterprise%20Storage%207.1pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP3-LTSSpkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP4-ESPOSpkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP4-LTSSpkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP5-ESPOSpkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP5-LTSSpkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Micro%205.1pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Micro%205.2pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Micro%205.3pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Micro%205.4pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Micro%205.5pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Basesystem%2015%20SP6pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Public%20Cloud%2012pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Public%20Cloud%2015%20SP4pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Python%203%2015%20SP6pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP3-LTSSpkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP4-LTSSpkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP5-LTSSpkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP3pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP4pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP5pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Micro%206.0pkg:rpm/suse/python-Jinja2&distro=SUSE%20Linux%20Micro%206.1pkg:rpm/suse/python-Jinja2&distro=SUSE%20Manager%20Client%20Tools%2012pkg:rpm/suse/python-Jinja2&distro=SUSE%20Manager%20Proxy%204.3pkg:rpm/suse/python-Jinja2&distro=SUSE%20Manager%20Server%204.3
< 2.10.4-r2+ 157 more
- (no CPE)range: < 2.10.4-r2
- (no CPE)range: < 2.10.4-r2
- (no CPE)range: < 2.10.4-r2
- (no CPE)range: < 1.37.1-r0
- (no CPE)range: < 1.37.1-r0
- (no CPE)range: < 2.61.0-r1
- (no CPE)range: < 3.2.432-r0
- (no CPE)range: < 2024.1.0-r13
- (no CPE)range: < 2024.1.0-r13
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 1.9.2-r3
- (no CPE)range: < 2.4.0-r0
- (no CPE)range: < 1.9.2-r3
- (no CPE)range: < 4.1.0-r0
- (no CPE)range: < 4.1.0-r0
- (no CPE)range: < 2.19.0-r2
- (no CPE)range: < 2.19.0-r2
- (no CPE)range: < 2.19.0-r2
- (no CPE)range: < 1.23.0-r6
- (no CPE)range: < 24.04.01-r1
- (no CPE)range: < 24.04.01-r1
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 0.18.1-r2
- (no CPE)range: < 0.18.1-r3
- (no CPE)range: < 0.6.6-r0
- (no CPE)range: < 0.6.6-r0
- (no CPE)range: < 0.18.1-r2
- (no CPE)range: < 0.18.1-r3
- (no CPE)range: < 0.6.6-r0
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 2.3.1-r1
- (no CPE)range: < 0.18.1-r2
- (no CPE)range: < 0.18.1-r3
- (no CPE)range: < 2.3.1-r1
- (no CPE)range: < 0.18.1-r2
- (no CPE)range: < 0.18.1-r3
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 0.18.1-r2
- (no CPE)range: < 0.18.1-r2
- (no CPE)range: < 0.18.1-r2
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 0.18.1-r1
- (no CPE)range: < 0.18.1-r1
- (no CPE)range: < 0.18.1-r1
- (no CPE)range: < 0.18.1-r1
- (no CPE)range: < 0.18.1-r1
- (no CPE)range: < 0.18.1-r1
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 0.6.7-r0
- (no CPE)range: < 4.1.1-r1
- (no CPE)range: < 4.1.1-r1
- (no CPE)range: < 4.1.1-r1
- (no CPE)range: < 4.1.1-r1
- (no CPE)range: < 2.10.4-r2
- (no CPE)range: < 2.10.4-r2
- (no CPE)range: < 2.10.4-r2
- (no CPE)range: < 1.37.1-r0
- (no CPE)range: < 1.37.1-r0
- (no CPE)range: < 3.2.432-r0
- (no CPE)range: < 2024.1.0-r13
- (no CPE)range: < 2024.1.0-r13
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 0.14.1-r0
- (no CPE)range: < 1.9.2-r3
- (no CPE)range: < 2.4.0-r0
- (no CPE)range: < 1.9.2-r3
- (no CPE)range: < 2.19.0-r2
- (no CPE)range: < 2.19.0-r2
- (no CPE)range: < 2.19.0-r2
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 3.9.1-r8
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 3.1.5-r0
- (no CPE)range: < 0.6.7-r0
- (no CPE)range: < 4.1.1-r1
- (no CPE)range: < 4.1.1-r1
- (no CPE)range: < 4.1.1-r1
- (no CPE)range: < 4.1.1-r1
- (no CPE)range: < 3.1.5
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 4.10.0-76.el9_5.4.alma.1
- (no CPE)range: < 2.11.3-7.el9_5
- (no CPE)range: < 3.54.1-1.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 0:4.10.0-76.el9_5.4
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 2.8-19.31.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 3.1.2-150400.12.11.1
- (no CPE)range: < 3.1.2-7.1
- (no CPE)range: < 3.1.4-slfo.1.1_2.1
- (no CPE)range: < 2.8-19.31.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- (no CPE)range: < 2.10.1-150000.3.18.1
- pallets/jinjav5Range: < 3.1.5
Patches
13 files changed · +63 −38
CHANGES.rst+3 −0 modified@@ -5,6 +5,9 @@ Version 3.1.5 Unreleased +- The sandboxed environment handles indirect calls to ``str.format``, such as + by passing a stored reference to a filter that calls its argument. + :ghsa:`q2x7-8rv6-6q7h` - Sandbox does not allow ``clear`` and ``pop`` on known mutable sequence types. :issue:`2032` - Calling sync ``render`` for an async template uses ``asyncio.run``.
src/jinja2/sandbox.py+43 −38 modified@@ -8,6 +8,7 @@ from _string import formatter_field_name_split # type: ignore from collections import abc from collections import deque +from functools import update_wrapper from string import Formatter from markupsafe import EscapeFormatter @@ -83,20 +84,6 @@ ) -def inspect_format_method(callable: t.Callable[..., t.Any]) -> t.Optional[str]: - if not isinstance( - callable, (types.MethodType, types.BuiltinMethodType) - ) or callable.__name__ not in ("format", "format_map"): - return None - - obj = callable.__self__ - - if isinstance(obj, str): - return obj - - return None - - def safe_range(*args: int) -> range: """A range that can't generate ranges with a length of more than MAX_RANGE items. @@ -316,6 +303,9 @@ def getitem( except AttributeError: pass else: + fmt = self.wrap_str_format(value) + if fmt is not None: + return fmt if self.is_safe_attribute(obj, argument, value): return value return self.unsafe_undefined(obj, argument) @@ -333,6 +323,9 @@ def getattr(self, obj: t.Any, attribute: str) -> t.Union[t.Any, Undefined]: except (TypeError, LookupError): pass else: + fmt = self.wrap_str_format(value) + if fmt is not None: + return fmt if self.is_safe_attribute(obj, attribute, value): return value return self.unsafe_undefined(obj, attribute) @@ -348,34 +341,49 @@ def unsafe_undefined(self, obj: t.Any, attribute: str) -> Undefined: exc=SecurityError, ) - def format_string( - self, - s: str, - args: t.Tuple[t.Any, ...], - kwargs: t.Dict[str, t.Any], - format_func: t.Optional[t.Callable[..., t.Any]] = None, - ) -> str: - """If a format call is detected, then this is routed through this - method so that our safety sandbox can be used for it. + def wrap_str_format(self, value: t.Any) -> t.Optional[t.Callable[..., str]]: + """If the given value is a ``str.format`` or ``str.format_map`` method, + return a new function than handles sandboxing. This is done at access + rather than in :meth:`call`, so that calls made without ``call`` are + also sandboxed. """ + if not isinstance( + value, (types.MethodType, types.BuiltinMethodType) + ) or value.__name__ not in ("format", "format_map"): + return None + + f_self: t.Any = value.__self__ + + if not isinstance(f_self, str): + return None + + str_type: t.Type[str] = type(f_self) + is_format_map = value.__name__ == "format_map" formatter: SandboxedFormatter - if isinstance(s, Markup): - formatter = SandboxedEscapeFormatter(self, escape=s.escape) + + if isinstance(f_self, Markup): + formatter = SandboxedEscapeFormatter(self, escape=f_self.escape) else: formatter = SandboxedFormatter(self) - if format_func is not None and format_func.__name__ == "format_map": - if len(args) != 1 or kwargs: - raise TypeError( - "format_map() takes exactly one argument" - f" {len(args) + (kwargs is not None)} given" - ) + vformat = formatter.vformat + + def wrapper(*args: t.Any, **kwargs: t.Any) -> str: + if is_format_map: + if kwargs: + raise TypeError("format_map() takes no keyword arguments") + + if len(args) != 1: + raise TypeError( + f"format_map() takes exactly one argument ({len(args)} given)" + ) + + kwargs = args[0] + args = () - kwargs = args[0] - args = () + return str_type(vformat(f_self, args, kwargs)) - rv = formatter.vformat(s, args, kwargs) - return type(s)(rv) + return update_wrapper(wrapper, value) def call( __self, # noqa: B902 @@ -385,9 +393,6 @@ def call( **kwargs: t.Any, ) -> t.Any: """Call an object from sandboxed code.""" - fmt = inspect_format_method(__obj) - if fmt is not None: - return __self.format_string(fmt, args, kwargs, __obj) # the double prefixes are to avoid double keyword argument # errors when proxying the call.
tests/test_security.py+17 −0 modified@@ -173,3 +173,20 @@ def test_safe_format_all_okay(self): '{{ ("a{x.foo}b{y}"|safe).format_map({"x":{"foo": 42}, "y":"<foo>"}) }}' ) assert t.render() == "a42b<foo>" + + def test_indirect_call(self): + def run(value, arg): + return value.run(arg) + + env = SandboxedEnvironment() + env.filters["run"] = run + t = env.from_string( + """{% set + ns = namespace(run="{0.__call__.__builtins__[__import__]}".format) + %} + {{ ns | run(not_here) }} + """ + ) + + with pytest.raises(SecurityError): + t.render()
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-q2x7-8rv6-6q7hghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-56326ghsaADVISORY
- github.com/pallets/jinja/commit/48b0687e05a5466a91cd5812d604fa37ad0943b4ghsax_refsource_MISCWEB
- github.com/pallets/jinja/releases/tag/3.1.5ghsax_refsource_MISCWEB
- github.com/pallets/jinja/security/advisories/GHSA-q2x7-8rv6-6q7hghsax_refsource_CONFIRMWEB
- lists.debian.org/debian-lts-announce/2025/04/msg00022.htmlghsaWEB
News mentions
0No linked articles in our index yet.