Skip to content

Commit

Permalink
Merge pull request from GHSA-h75v-3vvj-5mfj
Browse files Browse the repository at this point in the history
disallow invalid characters in keys to xmlattr filter
  • Loading branch information
davidism authored May 5, 2024
2 parents a7863ba + d655030 commit 0668239
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 10 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ Version 3.1.4

Unreleased

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


Version 3.1.3
-------------
Expand Down
22 changes: 17 additions & 5 deletions src/jinja2/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K
yield from value.items()


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


@pass_eval_context
Expand All @@ -259,8 +261,14 @@ def do_xmlattr(
) -> str:
"""Create an SGML/XML attribute string based on the items in a dict.
If any key contains a space, this fails with a ``ValueError``. Values that
are neither ``none`` nor ``undefined`` are automatically escaped.
**Values** that are neither ``none`` nor ``undefined`` are automatically
escaped, safely allowing untrusted user input.
User input should not be used as **keys** to this filter. If any key
contains a space, ``/`` solidus, ``>`` greater-than sign, or ``=`` equals
sign, this fails with a ``ValueError``. Regardless of this, user input
should never be used as keys to this filter, or must be separately validated
first.
.. sourcecode:: html+jinja
Expand All @@ -280,6 +288,10 @@ def do_xmlattr(
As you can see it automatically prepends a space in front of the item
if the filter returned something unless the second parameter is false.
.. versionchanged:: 3.1.4
Keys with ``/`` solidus, ``>`` greater-than sign, or ``=`` equals sign
are not allowed.
.. versionchanged:: 3.1.3
Keys with spaces are not allowed.
"""
Expand All @@ -289,8 +301,8 @@ def do_xmlattr(
if value is None or isinstance(value, Undefined):
continue

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

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

Expand Down
11 changes: 6 additions & 5 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,11 +474,12 @@ def test_xmlattr(self, env):
assert 'bar="23"' in out
assert 'blub:blub="<?>"' in out

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

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

0 comments on commit 0668239

Please # to comment.