VYPR
Medium severity6.3GHSA Advisory· Published Jun 13, 2025· Updated Apr 15, 2026

CVE-2025-22240

CVE-2025-22240

Description

Arbitrary directory creation or file deletion. In the find_file method of the GitFS class, a path is created using os.path.join using unvalidated input from the “tgt_env” variable. This can be exploited by an attacker to delete any file on the Master's process has permissions to.

AI Insight

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

Unvalidated input in Salt's GitFS find_file method allows path traversal, enabling arbitrary file deletion or directory creation on the master.

Vulnerability

Overview

The vulnerability resides in the find_file method of the GitFS fileserver class. A path is constructed using os.path.join from the unvalidated tgt_env parameter [1]. This allows an attacker to inject path traversal sequences (e.g., ../) into the resulting file path [2][3]. The fix replaces the unsafe salt.utils.path.join with the sanitized salt.utils.verify.clean_join function, which validates that the resulting path stays within the intended root directory [3].

Exploitation

An attacker who can influence the tgt_env argument passed to find_file can cause the master to reference paths outside of the intended GitFS cache directory [1][3]. The attack does not require authentication beyond normal minion access; a malicious or compromised minion can send crafted requests to the master [2][4]. The clean_join helper validates each component of the path against the root, effectively preventing directory traversal [3].

Impact

Successful exploitation allows the attacker to arbitrarily create directories or delete any file that the Salt master process has permission to modify [1]. This can lead to denial of service, information disclosure, or further compromise of the master host [4].

Mitigation

The vulnerability is patched in Salt version 3006.12, released as part of the June 2025 security release [4]. Users are advised to upgrade to this or a later patched version. The commit that applies the fix is available in the public repository [3].

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
saltPyPI
>= 3007.0rc1, < 3007.43007.4
saltPyPI
>= 3006.0rc1, < 3006.123006.12

Affected products

1

Patches

1
f7c28ffbf18d

Fix traversal in gitfs find_file

https://github.com/saltstack/saltDaniel A. WozniakApr 29, 2025via ghsa
3 files changed · +84 8
  • salt/utils/gitfs.py+5 4 modified
    @@ -3242,14 +3242,15 @@ def find_file(self, path, tgt_env="base", **kwargs):  # pylint: disable=W0613
             if os.path.isabs(path):
                 return fnd
     
    -        dest = salt.utils.path.join(self.cache_root, "refs", tgt_env, path)
    -        hashes_glob = salt.utils.path.join(
    +        # dest = salt.utils.path.join(self.cache_root, "refs", tgt_env, path)
    +        dest = salt.utils.verify.clean_join(self.cache_root, "refs", tgt_env, path)
    +        hashes_glob = salt.utils.verify.clean_join(
                 self.hash_cachedir, tgt_env, f"{path}.hash.*"
             )
    -        blobshadest = salt.utils.path.join(
    +        blobshadest = salt.utils.verify.clean_join(
                 self.hash_cachedir, tgt_env, f"{path}.hash.blob_sha1"
             )
    -        lk_fn = salt.utils.path.join(self.hash_cachedir, tgt_env, f"{path}.lk")
    +        lk_fn = salt.utils.verify.clean_join(self.hash_cachedir, tgt_env, f"{path}.lk")
             destdir = os.path.dirname(dest)
             hashdir = os.path.dirname(blobshadest)
             if not os.path.isdir(destdir):
    
  • salt/utils/verify.py+7 4 modified
    @@ -548,10 +548,13 @@ def clean_join(root, *paths, subdir=False, realpath=True):
         Performa a join and then check the result against the clean_path method. If
         clean_path fails a SaltValidationError is raised.
         """
    -    path = os.path.join(root, *paths)
    -    if not clean_path(root, path, subdir, realpath):
    -        raise SaltValidationError(f"Invalid path: {path!r}")
    -    return path
    +    parent = root
    +    for path in paths:
    +        child = os.path.join(parent, path)
    +        if not clean_path(parent, child, subdir, realpath):
    +            raise SaltValidationError(f"Invalid path: {path!r}")
    +        parent = child
    +    return child
     
     
     def valid_id(opts, id_):
    
  • tests/pytests/unit/utils/test_gitfs.py+72 0 modified
    @@ -4,6 +4,7 @@
     import pytest
     
     import salt.config
    +import salt.exceptions
     import salt.fileserver.gitfs
     import salt.utils.gitfs
     from salt.exceptions import FileserverConfigError
    @@ -262,3 +263,74 @@ def test_checkout_pygit2(_prepare_provider):
     )
     def test_get_cachedir_basename_pygit2(_prepare_provider):
         assert "_" == _prepare_provider.get_cache_basename()
    +
    +
    +def test_find_file(tmp_path):
    +    opts = {
    +        "cachedir": f"{tmp_path / 'cache'}",
    +        "gitfs_user": "",
    +        "gitfs_password": "",
    +        "gitfs_pubkey": "",
    +        "gitfs_privkey": "",
    +        "gitfs_passphrase": "",
    +        "gitfs_insecure_auth": False,
    +        "gitfs_refspecs": salt.config._DFLT_REFSPECS,
    +        "gitfs_ssl_verify": True,
    +        "gitfs_branch": "master",
    +        "gitfs_base": "master",
    +        "gitfs_root": "",
    +        "gitfs_env": "",
    +        "gitfs_fallback": "",
    +    }
    +    remotes = []
    +
    +    gitfs = salt.utils.gitfs.GitFS(opts, remotes)
    +    assert gitfs.find_file("asdf") == {"path": "", "rel": ""}
    +
    +
    +def test_find_file_bad_path(tmp_path):
    +    opts = {
    +        "cachedir": f"{tmp_path / 'cache'}",
    +        "gitfs_user": "",
    +        "gitfs_password": "",
    +        "gitfs_pubkey": "",
    +        "gitfs_privkey": "",
    +        "gitfs_passphrase": "",
    +        "gitfs_insecure_auth": False,
    +        "gitfs_refspecs": salt.config._DFLT_REFSPECS,
    +        "gitfs_ssl_verify": True,
    +        "gitfs_branch": "master",
    +        "gitfs_base": "master",
    +        "gitfs_root": "",
    +        "gitfs_env": "",
    +        "gitfs_fallback": "",
    +    }
    +    remotes = []
    +
    +    gitfs = salt.utils.gitfs.GitFS(opts, remotes)
    +    with pytest.raises(salt.exceptions.SaltValidationError):
    +        gitfs.find_file("sdf/../../../asdf")
    +
    +
    +def test_find_file_bad_env(tmp_path):
    +    opts = {
    +        "cachedir": f"{tmp_path / 'cache'}",
    +        "gitfs_user": "",
    +        "gitfs_password": "",
    +        "gitfs_pubkey": "",
    +        "gitfs_privkey": "",
    +        "gitfs_passphrase": "",
    +        "gitfs_insecure_auth": False,
    +        "gitfs_refspecs": salt.config._DFLT_REFSPECS,
    +        "gitfs_ssl_verify": True,
    +        "gitfs_branch": "master",
    +        "gitfs_base": "master",
    +        "gitfs_root": "",
    +        "gitfs_env": "",
    +        "gitfs_fallback": "",
    +    }
    +    remotes = []
    +
    +    gitfs = salt.utils.gitfs.GitFS(opts, remotes)
    +    with pytest.raises(salt.exceptions.SaltValidationError):
    +        gitfs.find_file("asdf", tgt_env="asd/../../../sdf")
    

Vulnerability mechanics

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

References

5

News mentions

0

No linked articles in our index yet.