VYPR
Moderate severityNVD Advisory· Published May 6, 2024· Updated Nov 3, 2025

Jinja vulnerable to HTML attribute injection when passing user input as keys to xmlattr filter

CVE-2024-34064

Description

Jinja is an extensible templating engine. The xmlattr filter in affected versions of Jinja accepts keys containing non-attribute characters. XML/HTML attributes cannot contain spaces, /, >, or =, as each would then be interpreted as starting a separate attribute. If an application accepts keys (as opposed to only values) as user input, and renders these in pages that other users see as well, an attacker could use this to inject other attributes and perform XSS. The fix for CVE-2024-22195 only addressed spaces but not other characters. Accepting keys as user input is now explicitly considered an unintended use case of the xmlattr filter, and code that does so without otherwise validating the input should be flagged as insecure, regardless of Jinja version. Accepting _values_ as user input continues to be safe. This vulnerability is fixed in 3.1.4.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Jinja's xmlattr filter allows attribute injection via keys containing special characters, enabling XSS when user input is used as keys; fixed in 3.1.4.

What the vulnerability is: The xmlattr filter in Jinja templating engine fails to properly sanitize keys for XML/HTML attributes. According to the HTML specification, attribute names cannot contain spaces, /, >, or = as these characters would break the attribute syntax and allow injection of additional attributes [1][2]. The previous fix for CVE-2024-22195 only addressed spaces, leaving the other characters unblocked [1].

How it is exploited: An attacker can supply a key containing characters like /, >, or = to the xmlattr filter. If an application accepts user input as attribute keys (rather than only values) and renders the output in a page viewed by other users, the attacker can inject arbitrary HTML attributes. This can lead to cross-site scripting (XSS) by injecting event handlers or other malicious attributes [1][2].

Impact: Successful exploitation allows an attacker to perform XSS attacks, potentially stealing cookies, session tokens, or performing actions on behalf of the victim. The Jinja project explicitly states that accepting user input as keys to xmlattr is an unintended use case and should be considered insecure regardless of version [1][2].

Mitigation: The vulnerability is fixed in Jinja version 3.1.4, which now rejects keys containing any of the forbidden characters [2]. Users should upgrade to 3.1.4 or later. Additionally, applications should never use user input as keys to xmlattr without thorough validation [1][2].

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.

PackageAffected versionsPatched versions
Jinja2PyPI
< 3.1.43.1.4

Affected products

115

Patches

1
0668239dc6b4

Merge pull request from GHSA-h75v-3vvj-5mfj

https://github.com/pallets/jinjaDavid LordMay 5, 2024via ghsa
3 files changed · +29 10
  • CHANGES.rst+6 0 modified
    @@ -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
     -------------
    
  • src/jinja2/filters.py+17 5 modified
    @@ -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
    @@ -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
     
    @@ -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.
         """
    @@ -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)}"')
     
    
  • tests/test_filters.py+6 5 modified
    @@ -474,11 +474,12 @@ def test_xmlattr(self, env):
             assert 'bar="23"' in out
             assert 'blub:blub="&lt;?&gt;"' 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) }}")
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

13

News mentions

0

No linked articles in our index yet.