VYPR
Low severityNVD Advisory· Published Mar 27, 2019· Updated Aug 4, 2024

CVE-2019-3828

CVE-2019-3828

Description

Ansible fetch module before versions 2.5.15, 2.6.14, 2.7.8 has a path traversal vulnerability which allows copying and overwriting files outside of the specified destination in the local ansible controller host, by not restricting an absolute path.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
ansiblePyPI
< 2.5.152.5.15
ansiblePyPI
>= 2.6.0a1, < 2.6.142.6.14
ansiblePyPI
>= 2.7.0a1, < 2.7.82.7.8

Affected products

1

Patches

3
f3edc091523f

[stable-2.5] Disallow use of remote home directories containing .. in their path (CVE-2019-3828) (#52133) (#52175)

https://github.com/ansible/ansibleMatt MartzFeb 18, 2019via ghsa
3 files changed · +44 23
  • changelogs/fragments/disallow-relative-homedir.yaml+3 0 added
    @@ -0,0 +1,3 @@
    +bugfixes:
    +- remote home directory - Disallow use of remote home directories that include
    +  relative pathing by means of `..` (CVE-2019-3828) (https://github.com/ansible/ansible/pull/52133)
    
  • lib/ansible/plugins/action/__init__.py+3 0 modified
    @@ -609,6 +609,9 @@ def _remote_expand_user(self, path, sudoable=True, pathsep=None):
             else:
                 expanded = initial_fragment
     
    +        if '..' in os.path.dirname(expanded).split('/'):
    +            raise AnsibleError("'%s' returned an invalid relative home directory path containing '..'" % self._play_context.remote_addr)
    +
             return expanded
     
         def _strip_success_message(self, data):
    
  • test/units/plugins/action/test_action.py+38 23 modified
    @@ -56,6 +56,28 @@
     """
     
     
    +def _action_base():
    +    fake_loader = DictDataLoader({
    +    })
    +    mock_module_loader = MagicMock()
    +    mock_shared_loader_obj = MagicMock()
    +    mock_shared_loader_obj.module_loader = mock_module_loader
    +    mock_connection_loader = MagicMock()
    +
    +    mock_shared_loader_obj.connection_loader = mock_connection_loader
    +    mock_connection = MagicMock()
    +
    +    play_context = MagicMock()
    +
    +    action_base = DerivedActionBase(task=None,
    +                                    connection=mock_connection,
    +                                    play_context=play_context,
    +                                    loader=fake_loader,
    +                                    templar=None,
    +                                    shared_loader_obj=mock_shared_loader_obj)
    +    return action_base
    +
    +
     class DerivedActionBase(ActionBase):
         TRANSFERS_FILES = False
     
    @@ -522,6 +544,18 @@ def test_action_base_sudo_only_if_user_differs(self):
             finally:
                 C.BECOME_ALLOW_SAME_USER = become_allow_same_user
     
    +    def test__remote_expand_user_relative_pathing(self):
    +        action_base = _action_base()
    +        action_base._play_context.remote_addr = 'bar'
    +        action_base._low_level_execute_command = MagicMock(return_value={'stdout': b'../home/user'})
    +        action_base._connection._shell.join_path.return_value = '../home/user/foo'
    +        with self.assertRaises(AnsibleError) as cm:
    +            action_base._remote_expand_user('~/foo')
    +        self.assertEqual(
    +            cm.exception.message,
    +            "'bar' returned an invalid relative home directory path containing '..'"
    +        )
    +
     
     class TestActionBaseCleanReturnedData(unittest.TestCase):
         def test(self):
    @@ -573,27 +607,8 @@ def fake_all(path_only=None):
     
     class TestActionBaseParseReturnedData(unittest.TestCase):
     
    -    def _action_base(self):
    -        fake_loader = DictDataLoader({
    -        })
    -        mock_module_loader = MagicMock()
    -        mock_shared_loader_obj = MagicMock()
    -        mock_shared_loader_obj.module_loader = mock_module_loader
    -        mock_connection_loader = MagicMock()
    -
    -        mock_shared_loader_obj.connection_loader = mock_connection_loader
    -        mock_connection = MagicMock()
    -
    -        action_base = DerivedActionBase(task=None,
    -                                        connection=mock_connection,
    -                                        play_context=None,
    -                                        loader=fake_loader,
    -                                        templar=None,
    -                                        shared_loader_obj=mock_shared_loader_obj)
    -        return action_base
    -
         def test_fail_no_json(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = 'foo\nbar\n'
             err = 'oopsy'
    @@ -607,7 +622,7 @@ def test_fail_no_json(self):
             self.assertEqual(res['module_stderr'], err)
     
         def test_json_empty(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '{}\n'
             err = ''
    @@ -621,7 +636,7 @@ def test_json_empty(self):
             self.assertFalse(res)
     
         def test_json_facts(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '{"ansible_facts": {"foo": "bar", "ansible_blip": "blip_value"}}\n'
             err = ''
    @@ -637,7 +652,7 @@ def test_json_facts(self):
             # self.assertIsInstance(res['ansible_facts'], AnsibleUnsafe)
     
         def test_json_facts_add_host(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '''{"ansible_facts": {"foo": "bar", "ansible_blip": "blip_value"},
             "add_host": {"host_vars": {"some_key": ["whatever the add_host object is"]}
    
396a2f747174

[stable-2.7] Disallow use of remote home directories containing .. in their path (CVE-2019-3828) (#52133) (#52173)

https://github.com/ansible/ansibleMatt MartzFeb 13, 2019via ghsa
3 files changed · +44 23
  • changelogs/fragments/disallow-relative-homedir.yaml+3 0 added
    @@ -0,0 +1,3 @@
    +bugfixes:
    +- remote home directory - Disallow use of remote home directories that include
    +  relative pathing by means of `..` (CVE-2019-3828) (https://github.com/ansible/ansible/pull/52133)
    
  • lib/ansible/plugins/action/__init__.py+3 0 modified
    @@ -614,6 +614,9 @@ def _remote_expand_user(self, path, sudoable=True, pathsep=None):
             else:
                 expanded = initial_fragment
     
    +        if '..' in os.path.dirname(expanded).split('/'):
    +            raise AnsibleError("'%s' returned an invalid relative home directory path containing '..'" % self._play_context.remote_addr)
    +
             return expanded
     
         def _strip_success_message(self, data):
    
  • test/units/plugins/action/test_action.py+38 23 modified
    @@ -56,6 +56,28 @@
     """
     
     
    +def _action_base():
    +    fake_loader = DictDataLoader({
    +    })
    +    mock_module_loader = MagicMock()
    +    mock_shared_loader_obj = MagicMock()
    +    mock_shared_loader_obj.module_loader = mock_module_loader
    +    mock_connection_loader = MagicMock()
    +
    +    mock_shared_loader_obj.connection_loader = mock_connection_loader
    +    mock_connection = MagicMock()
    +
    +    play_context = MagicMock()
    +
    +    action_base = DerivedActionBase(task=None,
    +                                    connection=mock_connection,
    +                                    play_context=play_context,
    +                                    loader=fake_loader,
    +                                    templar=None,
    +                                    shared_loader_obj=mock_shared_loader_obj)
    +    return action_base
    +
    +
     class DerivedActionBase(ActionBase):
         TRANSFERS_FILES = False
     
    @@ -526,6 +548,18 @@ def test_action_base_sudo_only_if_user_differs(self):
             finally:
                 C.BECOME_ALLOW_SAME_USER = become_allow_same_user
     
    +    def test__remote_expand_user_relative_pathing(self):
    +        action_base = _action_base()
    +        action_base._play_context.remote_addr = 'bar'
    +        action_base._low_level_execute_command = MagicMock(return_value={'stdout': b'../home/user'})
    +        action_base._connection._shell.join_path.return_value = '../home/user/foo'
    +        with self.assertRaises(AnsibleError) as cm:
    +            action_base._remote_expand_user('~/foo')
    +        self.assertEqual(
    +            cm.exception.message,
    +            "'bar' returned an invalid relative home directory path containing '..'"
    +        )
    +
     
     class TestActionBaseCleanReturnedData(unittest.TestCase):
         def test(self):
    @@ -577,27 +611,8 @@ def fake_all(path_only=None):
     
     class TestActionBaseParseReturnedData(unittest.TestCase):
     
    -    def _action_base(self):
    -        fake_loader = DictDataLoader({
    -        })
    -        mock_module_loader = MagicMock()
    -        mock_shared_loader_obj = MagicMock()
    -        mock_shared_loader_obj.module_loader = mock_module_loader
    -        mock_connection_loader = MagicMock()
    -
    -        mock_shared_loader_obj.connection_loader = mock_connection_loader
    -        mock_connection = MagicMock()
    -
    -        action_base = DerivedActionBase(task=None,
    -                                        connection=mock_connection,
    -                                        play_context=None,
    -                                        loader=fake_loader,
    -                                        templar=None,
    -                                        shared_loader_obj=mock_shared_loader_obj)
    -        return action_base
    -
         def test_fail_no_json(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = 'foo\nbar\n'
             err = 'oopsy'
    @@ -611,7 +626,7 @@ def test_fail_no_json(self):
             self.assertEqual(res['module_stderr'], err)
     
         def test_json_empty(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '{}\n'
             err = ''
    @@ -625,7 +640,7 @@ def test_json_empty(self):
             self.assertFalse(res)
     
         def test_json_facts(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '{"ansible_facts": {"foo": "bar", "ansible_blip": "blip_value"}}\n'
             err = ''
    @@ -641,7 +656,7 @@ def test_json_facts(self):
             # self.assertIsInstance(res['ansible_facts'], AnsibleUnsafe)
     
         def test_json_facts_add_host(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '''{"ansible_facts": {"foo": "bar", "ansible_blip": "blip_value"},
             "add_host": {"host_vars": {"some_key": ["whatever the add_host object is"]}
    
4be3215d2f9f

[stable-2.6] Disallow use of remote home directories containing .. in their path (CVE-2019-3828) (#52133)

https://github.com/ansible/ansibleMatt MartzFeb 13, 2019via ghsa
3 files changed · +44 23
  • changelogs/fragments/disallow-relative-homedir.yaml+3 0 added
    @@ -0,0 +1,3 @@
    +bugfixes:
    +- remote home directory - Disallow use of remote home directories that include
    +  relative pathing by means of `..` (CVE-2019-3828) (https://github.com/ansible/ansible/pull/52133)
    
  • lib/ansible/plugins/action/__init__.py+3 0 modified
    @@ -628,6 +628,9 @@ def _remote_expand_user(self, path, sudoable=True, pathsep=None):
             else:
                 expanded = initial_fragment
     
    +        if '..' in os.path.dirname(expanded).split('/'):
    +            raise AnsibleError("'%s' returned an invalid relative home directory path containing '..'" % self._play_context.remote_addr)
    +
             return expanded
     
         def _strip_success_message(self, data):
    
  • test/units/plugins/action/test_action.py+38 23 modified
    @@ -56,6 +56,28 @@
     """
     
     
    +def _action_base():
    +    fake_loader = DictDataLoader({
    +    })
    +    mock_module_loader = MagicMock()
    +    mock_shared_loader_obj = MagicMock()
    +    mock_shared_loader_obj.module_loader = mock_module_loader
    +    mock_connection_loader = MagicMock()
    +
    +    mock_shared_loader_obj.connection_loader = mock_connection_loader
    +    mock_connection = MagicMock()
    +
    +    play_context = MagicMock()
    +
    +    action_base = DerivedActionBase(task=None,
    +                                    connection=mock_connection,
    +                                    play_context=play_context,
    +                                    loader=fake_loader,
    +                                    templar=None,
    +                                    shared_loader_obj=mock_shared_loader_obj)
    +    return action_base
    +
    +
     class DerivedActionBase(ActionBase):
         TRANSFERS_FILES = False
     
    @@ -526,6 +548,18 @@ def test_action_base_sudo_only_if_user_differs(self):
             finally:
                 C.BECOME_ALLOW_SAME_USER = become_allow_same_user
     
    +    def test__remote_expand_user_relative_pathing(self):
    +        action_base = _action_base()
    +        action_base._play_context.remote_addr = 'bar'
    +        action_base._low_level_execute_command = MagicMock(return_value={'stdout': b'../home/user'})
    +        action_base._connection._shell.join_path.return_value = '../home/user/foo'
    +        with self.assertRaises(AnsibleError) as cm:
    +            action_base._remote_expand_user('~/foo')
    +        self.assertEqual(
    +            cm.exception.message,
    +            "'bar' returned an invalid relative home directory path containing '..'"
    +        )
    +
     
     class TestActionBaseCleanReturnedData(unittest.TestCase):
         def test(self):
    @@ -577,27 +611,8 @@ def fake_all(path_only=None):
     
     class TestActionBaseParseReturnedData(unittest.TestCase):
     
    -    def _action_base(self):
    -        fake_loader = DictDataLoader({
    -        })
    -        mock_module_loader = MagicMock()
    -        mock_shared_loader_obj = MagicMock()
    -        mock_shared_loader_obj.module_loader = mock_module_loader
    -        mock_connection_loader = MagicMock()
    -
    -        mock_shared_loader_obj.connection_loader = mock_connection_loader
    -        mock_connection = MagicMock()
    -
    -        action_base = DerivedActionBase(task=None,
    -                                        connection=mock_connection,
    -                                        play_context=None,
    -                                        loader=fake_loader,
    -                                        templar=None,
    -                                        shared_loader_obj=mock_shared_loader_obj)
    -        return action_base
    -
         def test_fail_no_json(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = 'foo\nbar\n'
             err = 'oopsy'
    @@ -611,7 +626,7 @@ def test_fail_no_json(self):
             self.assertEqual(res['module_stderr'], err)
     
         def test_json_empty(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '{}\n'
             err = ''
    @@ -625,7 +640,7 @@ def test_json_empty(self):
             self.assertFalse(res)
     
         def test_json_facts(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '{"ansible_facts": {"foo": "bar", "ansible_blip": "blip_value"}}\n'
             err = ''
    @@ -641,7 +656,7 @@ def test_json_facts(self):
             # self.assertIsInstance(res['ansible_facts'], AnsibleUnsafe)
     
         def test_json_facts_add_host(self):
    -        action_base = self._action_base()
    +        action_base = _action_base()
             rc = 0
             stdout = '''{"ansible_facts": {"foo": "bar", "ansible_blip": "blip_value"},
             "add_host": {"host_vars": {"some_key": ["whatever the add_host object is"]}
    

Vulnerability mechanics

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

References

16

News mentions

0

No linked articles in our index yet.