VYPR
High severityNVD Advisory· Published Apr 29, 2021· Updated Aug 3, 2024

CVE-2021-20228

CVE-2021-20228

Description

A flaw was found in the Ansible Engine 2.9.18, where sensitive info is not masked by default and is not protected by the no_log feature when using the sub-option feature of the basic.py module. This flaw allows an attacker to obtain sensitive information. The highest threat from this vulnerability is to confidentiality.

AI Insight

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

In Ansible Engine 2.9.18, the sub-option feature of basic.py module fails to mask sensitive info, allowing information disclosure.

Vulnerability

A flaw exists in Ansible Engine version 2.9.18 where the basic.py module's sub-option feature does not mask sensitive information by default, and the no_log attribute does not properly protect these values. This allows sensitive data to be exposed in logs or output. The affected version is Ansible Engine 2.9.18 [1][2].

Exploitation

An attacker who can observe Ansible task execution logs or output can obtain sensitive information, such as credentials or tokens, that are included as sub-option values. No special privileges are required beyond the ability to view Ansible output [2].

Impact

Successful exploitation leads to unauthorized disclosure of sensitive information, compromising confidentiality. The attacker gains access to data that should have been masked [1][2].

Mitigation

The issue is fixed in Ansible Engine via pull requests #73487 (for version 2.11) and #73493 (for version 2.9), which ensure that sub-option fallback values and defaults are masked with no_log [3][4]. Users should upgrade to patched versions or apply the relevant patches. No known workarounds exist for unpatched versions.

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.10.0a1, < 2.10.6rc12.10.6rc1
ansiblePyPI
>= 2.9.0a1, < 2.9.18rc12.9.18rc1
ansiblePyPI
< 2.8.19rc12.8.19rc1

Affected products

74

Patches

3
e41d1f0a3fd6

no_log mask suboption fallback values and defaults CVE-2021-20228 (#73487) (#73494)

https://github.com/ansible/ansibleJordan BoreanFeb 7, 2021via ghsa
7 files changed · +125 11
  • changelogs/fragments/no_log-fallback.yml+2 0 added
    @@ -0,0 +1,2 @@
    +security_fixes:
    +  - '**security issue** - Mask default and fallback values for ``no_log`` module options (CVE-2021-20228)'
    
  • lib/ansible/module_utils/basic.py+17 11 modified
    @@ -712,6 +712,9 @@ def __init__(self, argument_spec, bypass_checks=False, no_log=False,
                     if k not in self.argument_spec:
                         self.argument_spec[k] = v
     
    +        # Save parameter values that should never be logged
    +        self.no_log_values = set()
    +
             self._load_params()
             self._set_fallbacks()
     
    @@ -723,8 +726,6 @@ def __init__(self, argument_spec, bypass_checks=False, no_log=False,
                 print('\n{"failed": true, "msg": "Module alias error: %s"}' % to_native(e))
                 sys.exit(1)
     
    -        # Save parameter values that should never be logged
    -        self.no_log_values = set()
             self._handle_no_log_values()
     
             # check the locale as set by the current environment, and reset to
    @@ -1944,14 +1945,15 @@ def _set_defaults(self, pre=True, spec=None, param=None):
                 param = self.params
             for (k, v) in spec.items():
                 default = v.get('default', None)
    -            if pre is True:
    -                # this prevents setting defaults on required items
    -                if default is not None and k not in param:
    -                    param[k] = default
    -            else:
    -                # make sure things without a default still get set None
    -                if k not in param:
    -                    param[k] = default
    +
    +            # This prevents setting defaults on required items on the 1st run,
    +            # otherwise will set things without a default to None on the 2nd.
    +            if k not in param and (default is not None or not pre):
    +                # Make sure any default value for no_log fields are masked.
    +                if v.get('no_log', False) and default:
    +                    self.no_log_values.add(default)
    +
    +                param[k] = default
     
         def _set_fallbacks(self, spec=None, param=None):
             if spec is None:
    @@ -1971,9 +1973,13 @@ def _set_fallbacks(self, spec=None, param=None):
                         else:
                             fallback_args = item
                     try:
    -                    param[k] = fallback_strategy(*fallback_args, **fallback_kwargs)
    +                    fallback_value = fallback_strategy(*fallback_args, **fallback_kwargs)
                     except AnsibleFallbackNotFound:
                         continue
    +                else:
    +                    if v.get('no_log', False) and fallback_value:
    +                        self.no_log_values.add(fallback_value)
    +                    param[k] = fallback_value
     
         def _load_params(self):
             ''' read the input and set the params attribute.
    
  • test/integration/targets/module_utils/callback/pure_json.py+31 0 added
    @@ -0,0 +1,31 @@
    +# (c) 2021 Ansible Project
    +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
    +
    +from __future__ import (absolute_import, division, print_function)
    +__metaclass__ = type
    +
    +DOCUMENTATION = '''
    +    name: pure_json
    +    type: stdout
    +    short_description: only outputs the module results as json
    +'''
    +
    +import json
    +
    +from ansible.plugins.callback import CallbackBase
    +
    +
    +class CallbackModule(CallbackBase):
    +
    +    CALLBACK_VERSION = 2.0
    +    CALLBACK_TYPE = 'stdout'
    +    CALLBACK_NAME = 'pure_json'
    +
    +    def v2_runner_on_failed(self, result, ignore_errors=False):
    +        self._display.display(json.dumps(result._result))
    +
    +    def v2_runner_on_ok(self, result):
    +        self._display.display(json.dumps(result._result))
    +
    +    def v2_runner_on_skipped(self, result):
    +        self._display.display(json.dumps(result._result))
    
  • test/integration/targets/module_utils/library/test_no_log.py+35 0 added
    @@ -0,0 +1,35 @@
    +#!/usr/bin/python
    +# (c) 2021 Ansible Project
    +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
    +
    +from __future__ import absolute_import, division, print_function
    +__metaclass__ = type
    +
    +
    +from ansible.module_utils.basic import AnsibleModule, env_fallback
    +
    +
    +def main():
    +    module = AnsibleModule(
    +        argument_spec=dict(
    +            explicit_pass=dict(type='str', no_log=True),
    +            fallback_pass=dict(type='str', no_log=True, fallback=(env_fallback, ['SECRET_ENV'])),
    +            default_pass=dict(type='str', no_log=True, default='zyx'),
    +            normal=dict(type='str', default='plaintext'),
    +            suboption=dict(
    +                type='dict',
    +                options=dict(
    +                    explicit_sub_pass=dict(type='str', no_log=True),
    +                    fallback_sub_pass=dict(type='str', no_log=True, fallback=(env_fallback, ['SECRET_SUB_ENV'])),
    +                    default_sub_pass=dict(type='str', no_log=True, default='xvu'),
    +                    normal=dict(type='str', default='plaintext'),
    +                ),
    +            ),
    +        ),
    +    )
    +
    +    module.exit_json(changed=False)
    +
    +
    +if __name__ == '__main__':
    +    main()
    
  • test/integration/targets/module_utils/module_utils_test_no_log.yml+9 0 added
    @@ -0,0 +1,9 @@
    +# This is called by module_utils_vvvvv.yml with a custom callback
    +- hosts: testhost
    +  gather_facts: no
    +  tasks:
    +    - name: Check no_log invocation results
    +      test_no_log:
    +        explicit_pass: abc
    +        suboption:
    +          explicit_sub_pass: def
    
  • test/integration/targets/module_utils/module_utils_vvvvv.yml+27 0 added
    @@ -0,0 +1,27 @@
    +- hosts: testhost
    +  gather_facts: no
    +  tasks:
    +  # Invocation usually is output with 3vs or more, our callback plugin displays it anyway
    +  - name: Check no_log invocation results
    +    command: ansible-playbook -i {{ inventory_file }} module_utils_test_no_log.yml
    +    environment:
    +      ANSIBLE_CALLBACK_PLUGINS: callback
    +      ANSIBLE_STDOUT_CALLBACK: pure_json
    +      SECRET_ENV: ghi
    +      SECRET_SUB_ENV: jkl
    +    register: no_log_invocation
    +
    +  - set_fact:
    +      no_log_invocation: '{{ no_log_invocation.stdout | trim | from_json }}'
    +
    +  - name: check no log values from fallback or default are masked
    +    assert:
    +      that:
    +      - no_log_invocation.invocation.module_args.default_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.explicit_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.fallback_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.normal == 'plaintext'
    +      - no_log_invocation.invocation.module_args.suboption.default_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.explicit_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.fallback_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.normal == 'plaintext'
    
  • test/integration/targets/module_utils/runme.sh+4 0 modified
    @@ -4,6 +4,10 @@ set -eux
     
     ANSIBLE_ROLES_PATH=../ ansible-playbook module_utils_basic_setcwd.yml -i ../../inventory "$@"
     
    +# Keep the -vvvvv here. This acts as a test for testing that higher verbosity
    +# doesn't traceback with unicode in the custom module_utils directory path.
    +ansible-playbook module_utils_vvvvv.yml -i ../../inventory -vvvvv "$@"
    +
     ansible-playbook module_utils_test.yml -i ../../inventory -v "$@"
     ANSIBLE_MODULE_UTILS=other_mu_dir ansible-playbook module_utils_envvar.yml -i ../../inventory -v "$@"
     
    
49ebd509df9d

no_log mask suboption fallback values and defaults CVE-2021-20228 (#73487) (#73493)

https://github.com/ansible/ansibleJordan BoreanFeb 7, 2021via ghsa
7 files changed · +125 11
  • changelogs/fragments/no_log-fallback.yml+2 0 added
    @@ -0,0 +1,2 @@
    +security_fixes:
    +  - '**security issue** - Mask default and fallback values for ``no_log`` module options (CVE-2021-20228)'
    
  • lib/ansible/module_utils/basic.py+17 11 modified
    @@ -725,6 +725,9 @@ def __init__(self, argument_spec, bypass_checks=False, no_log=False,
                     if k not in self.argument_spec:
                         self.argument_spec[k] = v
     
    +        # Save parameter values that should never be logged
    +        self.no_log_values = set()
    +
             self._load_params()
             self._set_fallbacks()
     
    @@ -736,8 +739,6 @@ def __init__(self, argument_spec, bypass_checks=False, no_log=False,
                 print('\n{"failed": true, "msg": "Module alias error: %s"}' % to_native(e))
                 sys.exit(1)
     
    -        # Save parameter values that should never be logged
    -        self.no_log_values = set()
             self._handle_no_log_values()
     
             # check the locale as set by the current environment, and reset to
    @@ -1926,14 +1927,15 @@ def _set_defaults(self, pre=True, spec=None, param=None):
                 param = self.params
             for (k, v) in spec.items():
                 default = v.get('default', None)
    -            if pre is True:
    -                # this prevents setting defaults on required items
    -                if default is not None and k not in param:
    -                    param[k] = default
    -            else:
    -                # make sure things without a default still get set None
    -                if k not in param:
    -                    param[k] = default
    +
    +            # This prevents setting defaults on required items on the 1st run,
    +            # otherwise will set things without a default to None on the 2nd.
    +            if k not in param and (default is not None or not pre):
    +                # Make sure any default value for no_log fields are masked.
    +                if v.get('no_log', False) and default:
    +                    self.no_log_values.add(default)
    +
    +                param[k] = default
     
         def _set_fallbacks(self, spec=None, param=None):
             if spec is None:
    @@ -1953,9 +1955,13 @@ def _set_fallbacks(self, spec=None, param=None):
                         else:
                             fallback_args = item
                     try:
    -                    param[k] = fallback_strategy(*fallback_args, **fallback_kwargs)
    +                    fallback_value = fallback_strategy(*fallback_args, **fallback_kwargs)
                     except AnsibleFallbackNotFound:
                         continue
    +                else:
    +                    if v.get('no_log', False) and fallback_value:
    +                        self.no_log_values.add(fallback_value)
    +                    param[k] = fallback_value
     
         def _load_params(self):
             ''' read the input and set the params attribute.
    
  • test/integration/targets/module_utils/callback/pure_json.py+31 0 added
    @@ -0,0 +1,31 @@
    +# (c) 2021 Ansible Project
    +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
    +
    +from __future__ import (absolute_import, division, print_function)
    +__metaclass__ = type
    +
    +DOCUMENTATION = '''
    +    name: pure_json
    +    type: stdout
    +    short_description: only outputs the module results as json
    +'''
    +
    +import json
    +
    +from ansible.plugins.callback import CallbackBase
    +
    +
    +class CallbackModule(CallbackBase):
    +
    +    CALLBACK_VERSION = 2.0
    +    CALLBACK_TYPE = 'stdout'
    +    CALLBACK_NAME = 'pure_json'
    +
    +    def v2_runner_on_failed(self, result, ignore_errors=False):
    +        self._display.display(json.dumps(result._result))
    +
    +    def v2_runner_on_ok(self, result):
    +        self._display.display(json.dumps(result._result))
    +
    +    def v2_runner_on_skipped(self, result):
    +        self._display.display(json.dumps(result._result))
    
  • test/integration/targets/module_utils/library/test_no_log.py+35 0 added
    @@ -0,0 +1,35 @@
    +#!/usr/bin/python
    +# (c) 2021 Ansible Project
    +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
    +
    +from __future__ import absolute_import, division, print_function
    +__metaclass__ = type
    +
    +
    +from ansible.module_utils.basic import AnsibleModule, env_fallback
    +
    +
    +def main():
    +    module = AnsibleModule(
    +        argument_spec=dict(
    +            explicit_pass=dict(type='str', no_log=True),
    +            fallback_pass=dict(type='str', no_log=True, fallback=(env_fallback, ['SECRET_ENV'])),
    +            default_pass=dict(type='str', no_log=True, default='zyx'),
    +            normal=dict(type='str', default='plaintext'),
    +            suboption=dict(
    +                type='dict',
    +                options=dict(
    +                    explicit_sub_pass=dict(type='str', no_log=True),
    +                    fallback_sub_pass=dict(type='str', no_log=True, fallback=(env_fallback, ['SECRET_SUB_ENV'])),
    +                    default_sub_pass=dict(type='str', no_log=True, default='xvu'),
    +                    normal=dict(type='str', default='plaintext'),
    +                ),
    +            ),
    +        ),
    +    )
    +
    +    module.exit_json(changed=False)
    +
    +
    +if __name__ == '__main__':
    +    main()
    
  • test/integration/targets/module_utils/module_utils_test_no_log.yml+9 0 added
    @@ -0,0 +1,9 @@
    +# This is called by module_utils_vvvvv.yml with a custom callback
    +- hosts: testhost
    +  gather_facts: no
    +  tasks:
    +    - name: Check no_log invocation results
    +      test_no_log:
    +        explicit_pass: abc
    +        suboption:
    +          explicit_sub_pass: def
    
  • test/integration/targets/module_utils/module_utils_vvvvv.yml+27 0 added
    @@ -0,0 +1,27 @@
    +- hosts: testhost
    +  gather_facts: no
    +  tasks:
    +  # Invocation usually is output with 3vs or more, our callback plugin displays it anyway
    +  - name: Check no_log invocation results
    +    command: ansible-playbook -i {{ inventory_file }} module_utils_test_no_log.yml
    +    environment:
    +      ANSIBLE_CALLBACK_PLUGINS: callback
    +      ANSIBLE_STDOUT_CALLBACK: pure_json
    +      SECRET_ENV: ghi
    +      SECRET_SUB_ENV: jkl
    +    register: no_log_invocation
    +
    +  - set_fact:
    +      no_log_invocation: '{{ no_log_invocation.stdout | trim | from_json }}'
    +
    +  - name: check no log values from fallback or default are masked
    +    assert:
    +      that:
    +      - no_log_invocation.invocation.module_args.default_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.explicit_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.fallback_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.normal == 'plaintext'
    +      - no_log_invocation.invocation.module_args.suboption.default_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.explicit_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.fallback_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.normal == 'plaintext'
    
  • test/integration/targets/module_utils/runme.sh+4 0 modified
    @@ -2,5 +2,9 @@
     
     set -eux
     
    +# Keep the -vvvvv here. This acts as a test for testing that higher verbosity
    +# doesn't traceback with unicode in the custom module_utils directory path.
    +ansible-playbook module_utils_vvvvv.yml -i ../../inventory -vvvvv "$@"
    +
     ansible-playbook module_utils_test.yml -i ../../inventory -v "$@"
     ANSIBLE_MODULE_UTILS=other_mu_dir ansible-playbook module_utils_envvar.yml -i ../../inventory -v "$@"
    
f8ff395d817c

no_log mask suboption fallback values and defaults CVE-2021-20228 (#73487) (#73492)

https://github.com/ansible/ansibleJordan BoreanFeb 5, 2021via ghsa
7 files changed · +125 11
  • changelogs/fragments/no_log-fallback.yml+2 0 added
    @@ -0,0 +1,2 @@
    +security_fixes:
    +  - '**security issue** - Mask default and fallback values for ``no_log`` module options (CVE-2021-20228)'
    
  • lib/ansible/module_utils/basic.py+17 11 modified
    @@ -720,6 +720,9 @@ def __init__(self, argument_spec, bypass_checks=False, no_log=False,
                     if k not in self.argument_spec:
                         self.argument_spec[k] = v
     
    +        # Save parameter values that should never be logged
    +        self.no_log_values = set()
    +
             self._load_params()
             self._set_fallbacks()
     
    @@ -731,8 +734,6 @@ def __init__(self, argument_spec, bypass_checks=False, no_log=False,
                 print('\n{"failed": true, "msg": "Module alias error: %s"}' % to_native(e))
                 sys.exit(1)
     
    -        # Save parameter values that should never be logged
    -        self.no_log_values = set()
             self._handle_no_log_values()
     
             # check the locale as set by the current environment, and reset to
    @@ -1893,14 +1894,15 @@ def _set_defaults(self, pre=True, spec=None, param=None):
                 param = self.params
             for (k, v) in spec.items():
                 default = v.get('default', None)
    -            if pre is True:
    -                # this prevents setting defaults on required items
    -                if default is not None and k not in param:
    -                    param[k] = default
    -            else:
    -                # make sure things without a default still get set None
    -                if k not in param:
    -                    param[k] = default
    +
    +            # This prevents setting defaults on required items on the 1st run,
    +            # otherwise will set things without a default to None on the 2nd.
    +            if k not in param and (default is not None or not pre):
    +                # Make sure any default value for no_log fields are masked.
    +                if v.get('no_log', False) and default:
    +                    self.no_log_values.add(default)
    +
    +                param[k] = default
     
         def _set_fallbacks(self, spec=None, param=None):
             if spec is None:
    @@ -1920,9 +1922,13 @@ def _set_fallbacks(self, spec=None, param=None):
                         else:
                             fallback_args = item
                     try:
    -                    param[k] = fallback_strategy(*fallback_args, **fallback_kwargs)
    +                    fallback_value = fallback_strategy(*fallback_args, **fallback_kwargs)
                     except AnsibleFallbackNotFound:
                         continue
    +                else:
    +                    if v.get('no_log', False) and fallback_value:
    +                        self.no_log_values.add(fallback_value)
    +                    param[k] = fallback_value
     
         def _load_params(self):
             ''' read the input and set the params attribute.
    
  • test/integration/targets/module_utils/callback/pure_json.py+31 0 added
    @@ -0,0 +1,31 @@
    +# (c) 2021 Ansible Project
    +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
    +
    +from __future__ import (absolute_import, division, print_function)
    +__metaclass__ = type
    +
    +DOCUMENTATION = '''
    +    name: pure_json
    +    type: stdout
    +    short_description: only outputs the module results as json
    +'''
    +
    +import json
    +
    +from ansible.plugins.callback import CallbackBase
    +
    +
    +class CallbackModule(CallbackBase):
    +
    +    CALLBACK_VERSION = 2.0
    +    CALLBACK_TYPE = 'stdout'
    +    CALLBACK_NAME = 'pure_json'
    +
    +    def v2_runner_on_failed(self, result, ignore_errors=False):
    +        self._display.display(json.dumps(result._result))
    +
    +    def v2_runner_on_ok(self, result):
    +        self._display.display(json.dumps(result._result))
    +
    +    def v2_runner_on_skipped(self, result):
    +        self._display.display(json.dumps(result._result))
    
  • test/integration/targets/module_utils/library/test_no_log.py+35 0 added
    @@ -0,0 +1,35 @@
    +#!/usr/bin/python
    +# (c) 2021 Ansible Project
    +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
    +
    +from __future__ import absolute_import, division, print_function
    +__metaclass__ = type
    +
    +
    +from ansible.module_utils.basic import AnsibleModule, env_fallback
    +
    +
    +def main():
    +    module = AnsibleModule(
    +        argument_spec=dict(
    +            explicit_pass=dict(type='str', no_log=True),
    +            fallback_pass=dict(type='str', no_log=True, fallback=(env_fallback, ['SECRET_ENV'])),
    +            default_pass=dict(type='str', no_log=True, default='zyx'),
    +            normal=dict(type='str', default='plaintext'),
    +            suboption=dict(
    +                type='dict',
    +                options=dict(
    +                    explicit_sub_pass=dict(type='str', no_log=True),
    +                    fallback_sub_pass=dict(type='str', no_log=True, fallback=(env_fallback, ['SECRET_SUB_ENV'])),
    +                    default_sub_pass=dict(type='str', no_log=True, default='xvu'),
    +                    normal=dict(type='str', default='plaintext'),
    +                ),
    +            ),
    +        ),
    +    )
    +
    +    module.exit_json(changed=False)
    +
    +
    +if __name__ == '__main__':
    +    main()
    
  • test/integration/targets/module_utils/module_utils_test_no_log.yml+9 0 added
    @@ -0,0 +1,9 @@
    +# This is called by module_utils_vvvvv.yml with a custom callback
    +- hosts: testhost
    +  gather_facts: no
    +  tasks:
    +    - name: Check no_log invocation results
    +      test_no_log:
    +        explicit_pass: abc
    +        suboption:
    +          explicit_sub_pass: def
    
  • test/integration/targets/module_utils/module_utils_vvvvv.yml+27 0 added
    @@ -0,0 +1,27 @@
    +- hosts: testhost
    +  gather_facts: no
    +  tasks:
    +  # Invocation usually is output with 3vs or more, our callback plugin displays it anyway
    +  - name: Check no_log invocation results
    +    command: ansible-playbook -i {{ inventory_file }} module_utils_test_no_log.yml
    +    environment:
    +      ANSIBLE_CALLBACK_PLUGINS: callback
    +      ANSIBLE_STDOUT_CALLBACK: pure_json
    +      SECRET_ENV: ghi
    +      SECRET_SUB_ENV: jkl
    +    register: no_log_invocation
    +
    +  - set_fact:
    +      no_log_invocation: '{{ no_log_invocation.stdout | trim | from_json }}'
    +
    +  - name: check no log values from fallback or default are masked
    +    assert:
    +      that:
    +      - no_log_invocation.invocation.module_args.default_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.explicit_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.fallback_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.normal == 'plaintext'
    +      - no_log_invocation.invocation.module_args.suboption.default_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.explicit_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.fallback_sub_pass == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER'
    +      - no_log_invocation.invocation.module_args.suboption.normal == 'plaintext'
    
  • test/integration/targets/module_utils/runme.sh+4 0 modified
    @@ -2,5 +2,9 @@
     
     set -eux
     
    +# Keep the -vvvvv here. This acts as a test for testing that higher verbosity
    +# doesn't traceback with unicode in the custom module_utils directory path.
    +ansible-playbook module_utils_vvvvv.yml -i ../../inventory -vvvvv "$@"
    +
     ansible-playbook module_utils_test.yml -i ../../inventory -v "$@"
     ANSIBLE_MODULE_UTILS=other_mu_dir ansible-playbook module_utils_envvar.yml -i ../../inventory -v "$@"
    

Vulnerability mechanics

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

References

12

News mentions

0

No linked articles in our index yet.