Skip to content

Commit 0668239

Browse files
authored
Merge pull request from GHSA-h75v-3vvj-5mfj
disallow invalid characters in keys to xmlattr filter
2 parents a7863ba + d655030 commit 0668239

File tree

3 files changed

+29
-10
lines changed

3 files changed

+29
-10
lines changed

CHANGES.rst

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ Version 3.1.4
55

66
Unreleased
77

8+
- The ``xmlattr`` filter does not allow keys with ``/`` solidus, ``>``
9+
greater-than sign, or ``=`` equals sign, in addition to disallowing spaces.
10+
Regardless of any validation done by Jinja, user input should never be used
11+
as keys to this filter, or must be separately validated first.
12+
GHSA-h75v-3vvj-5mfj
13+
814

915
Version 3.1.3
1016
-------------

src/jinja2/filters.py

+17-5
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K
250250
yield from value.items()
251251

252252

253-
_space_re = re.compile(r"\s", flags=re.ASCII)
253+
# Check for characters that would move the parser state from key to value.
254+
# https://html.spec.whatwg.org/#attribute-name-state
255+
_attr_key_re = re.compile(r"[\s/>=]", flags=re.ASCII)
254256

255257

256258
@pass_eval_context
@@ -259,8 +261,14 @@ def do_xmlattr(
259261
) -> str:
260262
"""Create an SGML/XML attribute string based on the items in a dict.
261263
262-
If any key contains a space, this fails with a ``ValueError``. Values that
263-
are neither ``none`` nor ``undefined`` are automatically escaped.
264+
**Values** that are neither ``none`` nor ``undefined`` are automatically
265+
escaped, safely allowing untrusted user input.
266+
267+
User input should not be used as **keys** to this filter. If any key
268+
contains a space, ``/`` solidus, ``>`` greater-than sign, or ``=`` equals
269+
sign, this fails with a ``ValueError``. Regardless of this, user input
270+
should never be used as keys to this filter, or must be separately validated
271+
first.
264272
265273
.. sourcecode:: html+jinja
266274
@@ -280,6 +288,10 @@ def do_xmlattr(
280288
As you can see it automatically prepends a space in front of the item
281289
if the filter returned something unless the second parameter is false.
282290
291+
.. versionchanged:: 3.1.4
292+
Keys with ``/`` solidus, ``>`` greater-than sign, or ``=`` equals sign
293+
are not allowed.
294+
283295
.. versionchanged:: 3.1.3
284296
Keys with spaces are not allowed.
285297
"""
@@ -289,8 +301,8 @@ def do_xmlattr(
289301
if value is None or isinstance(value, Undefined):
290302
continue
291303

292-
if _space_re.search(key) is not None:
293-
raise ValueError(f"Spaces are not allowed in attributes: '{key}'")
304+
if _attr_key_re.search(key) is not None:
305+
raise ValueError(f"Invalid character in attribute name: {key!r}")
294306

295307
items.append(f'{escape(key)}="{escape(value)}"')
296308

tests/test_filters.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -474,11 +474,12 @@ def test_xmlattr(self, env):
474474
assert 'bar="23"' in out
475475
assert 'blub:blub="<?>"' in out
476476

477-
def test_xmlattr_key_with_spaces(self, env):
478-
with pytest.raises(ValueError, match="Spaces are not allowed"):
479-
env.from_string(
480-
"{{ {'src=1 onerror=alert(1)': 'my_class'}|xmlattr }}"
481-
).render()
477+
@pytest.mark.parametrize("sep", ("\t", "\n", "\f", " ", "/", ">", "="))
478+
def test_xmlattr_key_invalid(self, env: Environment, sep: str) -> None:
479+
with pytest.raises(ValueError, match="Invalid character"):
480+
env.from_string("{{ {key: 'my_class'}|xmlattr }}").render(
481+
key=f"class{sep}onclick=alert(1)"
482+
)
482483

483484
def test_sort1(self, env):
484485
tmpl = env.from_string("{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}")

0 commit comments

Comments
 (0)