attr filter uses env.getattr
This commit is contained in:
parent
033c20015c
commit
065334d1ee
@ -5,6 +5,10 @@ Version 3.1.6
|
||||
|
||||
Unreleased
|
||||
|
||||
- The ``|attr`` filter does not bypass the environment's attribute lookup,
|
||||
allowing the sandbox to apply its checks. :ghsa:`cpwx-vrp4-4pq7`
|
||||
|
||||
|
||||
Version 3.1.5
|
||||
-------------
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import re
|
||||
import typing
|
||||
import typing as t
|
||||
from collections import abc
|
||||
from inspect import getattr_static
|
||||
from itertools import chain
|
||||
from itertools import groupby
|
||||
|
||||
@ -1411,31 +1412,25 @@ def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]
|
||||
def do_attr(
|
||||
environment: "Environment", obj: t.Any, name: str
|
||||
) -> t.Union[Undefined, t.Any]:
|
||||
"""Get an attribute of an object. ``foo|attr("bar")`` works like
|
||||
``foo.bar`` just that always an attribute is returned and items are not
|
||||
looked up.
|
||||
"""Get an attribute of an object. ``foo|attr("bar")`` works like
|
||||
``foo.bar``, but returns undefined instead of falling back to ``foo["bar"]``
|
||||
if the attribute doesn't exist.
|
||||
|
||||
See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
|
||||
"""
|
||||
# Environment.getattr will fall back to obj[name] if obj.name doesn't exist.
|
||||
# But we want to call env.getattr to get behavior such as sandboxing.
|
||||
# Determine if the attr exists first, so we know the fallback won't trigger.
|
||||
try:
|
||||
name = str(name)
|
||||
except UnicodeError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
value = getattr(obj, name)
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if environment.sandboxed:
|
||||
environment = t.cast("SandboxedEnvironment", environment)
|
||||
# This avoids executing properties/descriptors, but misses __getattr__
|
||||
# and __getattribute__ dynamic attrs.
|
||||
getattr_static(obj, name)
|
||||
except AttributeError:
|
||||
# This finds dynamic attrs, and we know it's not a descriptor at this point.
|
||||
if not hasattr(obj, name):
|
||||
return environment.undefined(obj=obj, name=name)
|
||||
|
||||
if not environment.is_safe_attribute(obj, name, value):
|
||||
return environment.unsafe_undefined(obj, name)
|
||||
|
||||
return value
|
||||
|
||||
return environment.undefined(obj=obj, name=name)
|
||||
return environment.getattr(obj, name)
|
||||
|
||||
|
||||
@typing.overload
|
||||
|
||||
@ -190,3 +190,13 @@ class TestStringFormatMap:
|
||||
|
||||
with pytest.raises(SecurityError):
|
||||
t.render()
|
||||
|
||||
def test_attr_filter(self) -> None:
|
||||
env = SandboxedEnvironment()
|
||||
t = env.from_string(
|
||||
"""{{ "{0.__call__.__builtins__[__import__]}"
|
||||
| attr("format")(not_here) }}"""
|
||||
)
|
||||
|
||||
with pytest.raises(SecurityError):
|
||||
t.render()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user