VYPR
High severityNVD Advisory· Published Sep 22, 2021· Updated Aug 3, 2024

CVE-2021-3583

CVE-2021-3583

Description

A flaw was found in Ansible, where a user's controller is vulnerable to template injection. This issue can occur through facts used in the template if the user is trying to put templates in multi-line YAML strings and the facts being handled do not routinely include special template characters. This flaw allows attackers to perform command injection, which discloses sensitive information. The highest threat from this vulnerability is to confidentiality and integrity.

AI Insight

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

Ansible controller template injection via multi-line YAML facts allows command injection and info disclosure.

Vulnerability

A template injection flaw exists in Ansible's handling of facts used in Jinja2 templates, specifically when multi-line YAML strings are used and the facts do not routinely contain special template characters. This can allow unsanitized template syntax within facts to be evaluated, leading to code injection. Affected versions are those prior to the merge of pull request #74960 [2].

Exploitation

An attacker who can control the facts processed by an Ansible controller's template engine can inject Jinja2 template syntax. The attacker does not need authentication if they can supply facts, for example, through a compromised managed node or by being a malicious user with inventory write access. The user must have a playbook that uses multi-line YAML strings for templates, and the facts must be included in such a template. The injected template code is then executed on the controller when the playbook runs [1][3].

Impact

Successful exploitation allows the attacker to perform command injection on the Ansible controller, leading to disclosure of sensitive information and potential integrity compromise of the automation environment. The CVSS v3.1 base score is 8.1 (High) with vector AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N [3].

Mitigation

The vulnerability was addressed by pull request #74960, which ensures that unsafe template markup is preserved across newlines [2]. Users are advised to update to a version of Ansible that includes this fix. As a workaround, avoid using multi-line YAML strings for templates that incorporate untrusted facts until the fix can be applied. No EOL or KEV listing is noted [1][2].

AI Insight generated on May 21, 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
ansiblePyPI
< 2.9.23rc12.9.23rc1
ansiblePyPI
>= 2.10.0a1, < 2.10.11rc12.10.11rc1
ansiblePyPI
>= 2.11.0a1, < 2.11.2rc12.11.2rc1

Affected products

73

Patches

3
8b17e5b9229f

fix unsafe preservation across newlines (#74960) (#74976)

https://github.com/ansible/ansibleBrian CocaJun 11, 2021via ghsa
4 files changed · +29 1
  • changelogs/fragments/fix_unsafe_newline.yml+2 0 added
    @@ -0,0 +1,2 @@
    +security_fixes:
    +  - templating engine fix for not preserving usnafe status when trying to preserve newlines. CVE-2021-3583
    
  • lib/ansible/template/__init__.py+4 1 modified
    @@ -875,7 +875,8 @@ def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=
     
                 try:
                     res = j2_concat(rf)
    -                if getattr(new_context, 'unsafe', False):
    +                unsafe = getattr(new_context, 'unsafe', False)
    +                if unsafe:
                         res = wrap_var(res)
                 except TypeError as te:
                     if 'AnsibleUndefined' in to_native(te):
    @@ -905,6 +906,8 @@ def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=
                     res_newlines = _count_newlines_from_end(res)
                     if data_newlines > res_newlines:
                         res += self.environment.newline_sequence * (data_newlines - res_newlines)
    +                    if unsafe:
    +                        res = wrap_var(res)
                 return res
             except (UndefinedError, AnsibleUndefinedVariable) as e:
                 if fail_on_undefined:
    
  • test/integration/targets/template/runme.sh+4 0 modified
    @@ -34,3 +34,7 @@ ansible-playbook 6653.yml -v "$@"
     
     # https://github.com/ansible/ansible/issues/72262
     ansible-playbook 72262.yml -v "$@"
    +
    +# ensure unsafe is preserved, even with extra newlines
    +ansible-playbook unsafe.yml -v "$@"
    +
    
  • test/integration/targets/template/unsafe.yml+19 0 added
    @@ -0,0 +1,19 @@
    +- hosts: localhost
    +  gather_facts: false
    +  vars:
    +    nottemplated: this should not be seen
    +    imunsafe: !unsafe '{{ nottemplated }}'
    +  tasks:
    +
    +    - set_fact:
    +        this_was_unsafe: >
    +          {{ imunsafe }}
    +
    +    - set_fact:
    +          this_always_safe: '{{ imunsafe }}'
    +
    +    - name: ensure nothing was templated
    +      assert:
    +        that:
    +        - this_always_safe == imunsafe
    +        - imunsafe == this_was_unsafe.strip()
    
8aa850e3573e

fix unsafe preservation across newlines (#74960) (#74975)

https://github.com/ansible/ansibleBrian CocaJun 11, 2021via ghsa
4 files changed · +29 1
  • changelogs/fragments/fix_unsafe_newline.yml+2 0 added
    @@ -0,0 +1,2 @@
    +security_fixes:
    +  - templating engine fix for not preserving usnafe status when trying to preserve newlines. CVE-2021-3583
    
  • lib/ansible/template/__init__.py+4 1 modified
    @@ -1064,7 +1064,8 @@ def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=
     
                 try:
                     res = j2_concat(rf)
    -                if getattr(new_context, 'unsafe', False):
    +                unsafe = getattr(new_context, 'unsafe', False)
    +                if unsafe:
                         res = wrap_var(res)
                 except TypeError as te:
                     if 'AnsibleUndefined' in to_native(te):
    @@ -1094,6 +1095,8 @@ def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=
                     res_newlines = _count_newlines_from_end(res)
                     if data_newlines > res_newlines:
                         res += self.environment.newline_sequence * (data_newlines - res_newlines)
    +                    if unsafe:
    +                        res = wrap_var(res)
                 return res
             except (UndefinedError, AnsibleUndefinedVariable) as e:
                 if fail_on_undefined:
    
  • test/integration/targets/template/runme.sh+4 0 modified
    @@ -34,3 +34,7 @@ ansible-playbook 6653.yml -v "$@"
     
     # https://github.com/ansible/ansible/issues/72262
     ansible-playbook 72262.yml -v "$@"
    +
    +# ensure unsafe is preserved, even with extra newlines
    +ansible-playbook unsafe.yml -v "$@"
    +
    
  • test/integration/targets/template/unsafe.yml+19 0 added
    @@ -0,0 +1,19 @@
    +- hosts: localhost
    +  gather_facts: false
    +  vars:
    +    nottemplated: this should not be seen
    +    imunsafe: !unsafe '{{ nottemplated }}'
    +  tasks:
    +
    +    - set_fact:
    +        this_was_unsafe: >
    +          {{ imunsafe }}
    +
    +    - set_fact:
    +          this_always_safe: '{{ imunsafe }}'
    +
    +    - name: ensure nothing was templated
    +      assert:
    +        that:
    +        - this_always_safe == imunsafe
    +        - imunsafe == this_was_unsafe.strip()
    
03aff644cc1c

fix unsafe preservation across newlines (#74960) (#74973)

https://github.com/ansible/ansibleBrian CocaJun 11, 2021via ghsa
4 files changed · +29 1
  • changelogs/fragments/fix_unsafe_newline.yml+2 0 added
    @@ -0,0 +1,2 @@
    +security_fixes:
    +  - templating engine fix for not preserving usnafe status when trying to preserve newlines. CVE-2021-3583
    
  • lib/ansible/template/__init__.py+4 1 modified
    @@ -1092,7 +1092,8 @@ def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=
                         res = ansible_native_concat(rf)
                     else:
                         res = j2_concat(rf)
    -                if getattr(new_context, 'unsafe', False):
    +                unsafe = getattr(new_context, 'unsafe', False)
    +                if unsafe:
                         res = wrap_var(res)
                 except TypeError as te:
                     if 'AnsibleUndefined' in to_native(te):
    @@ -1122,6 +1123,8 @@ def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=
                     res_newlines = _count_newlines_from_end(res)
                     if data_newlines > res_newlines:
                         res += self.environment.newline_sequence * (data_newlines - res_newlines)
    +                    if unsafe:
    +                        res = wrap_var(res)
                 return res
             except (UndefinedError, AnsibleUndefinedVariable) as e:
                 if fail_on_undefined:
    
  • test/integration/targets/template/runme.sh+4 0 modified
    @@ -34,3 +34,7 @@ ansible-playbook 6653.yml -v "$@"
     
     # https://github.com/ansible/ansible/issues/72262
     ansible-playbook 72262.yml -v "$@"
    +
    +# ensure unsafe is preserved, even with extra newlines
    +ansible-playbook unsafe.yml -v "$@"
    +
    
  • test/integration/targets/template/unsafe.yml+19 0 added
    @@ -0,0 +1,19 @@
    +- hosts: localhost
    +  gather_facts: false
    +  vars:
    +    nottemplated: this should not be seen
    +    imunsafe: !unsafe '{{ nottemplated }}'
    +  tasks:
    +
    +    - set_fact:
    +        this_was_unsafe: >
    +          {{ imunsafe }}
    +
    +    - set_fact:
    +          this_always_safe: '{{ imunsafe }}'
    +
    +    - name: ensure nothing was templated
    +      assert:
    +        that:
    +        - this_always_safe == imunsafe
    +        - imunsafe == this_was_unsafe.strip()
    

Vulnerability mechanics

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

References

9

News mentions

0

No linked articles in our index yet.