CVE-2025-8406
Executive Summary
CVE-2025-8406 is a path traversal vulnerability in ZenML version 0.83.1, specifically in the PathMaterializer class. The load function uses is_path_within_directory to validate files during data.tar.gz extraction, but this validation fails to effectively detect symbolic and hard links. This flaw allows an attacker to write arbitrary files to the filesystem, potentially leading to arbitrary command execution if critical files (e.g., SSH keys, configuration files, or system binaries) are overwritten. The vulnerability has a CVSS score of 6.3 (Medium), but the potential impact is high due to the possibility of privilege escalation or remote code execution in a CI/CD pipeline context. No public exploit or patch is currently available.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects the Python package zenml (PyPI). Organizations using ZenML in their MLOps pipelines should immediately assess their exposure. The package is used for machine learning pipeline orchestration, and a compromise could lead to data exfiltration, model poisoning, or lateral movement within the infrastructure.
CVSS Breakdown & Threat Level
- CVSS Score: 6.3 (Medium)
- Vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
- Attack Vector: Local (AV:L) – The attacker must have local access to the system or be able to supply a malicious
data.tar.gzfile. - Attack Complexity: Low (AC:L) – No special conditions are required.
- Privileges Required: Low (PR:L) – The attacker needs low-level privileges to trigger the extraction.
- User Interaction: None (UI:N) – No user action is required beyond the extraction process.
- Scope: Unchanged (S:U) – The vulnerability does not affect other components.
- Confidentiality Impact: High (C:H) – Arbitrary file read is possible via symlink traversal.
- Integrity Impact: High (I:H) – Arbitrary file write can overwrite critical files.
- Availability Impact: High (A:H) – Overwriting system files can lead to denial of service.
Threat Level: Medium, but with high potential for escalation in CI/CD environments.
Deep Dive & Mechanics
The vulnerability resides in the PathMaterializer class, specifically in the load method. When a data.tar.gz file is extracted, the code attempts to validate that extracted files stay within the intended directory using is_path_within_directory. However, this function does not properly handle symbolic links (symlinks) or hard links. An attacker can craft a tar archive containing a symlink that points to an arbitrary location (e.g., /etc/passwd or ~/.ssh/authorized_keys). When the archive is extracted, the symlink is created, and subsequent file writes through that symlink bypass the path validation, allowing writes to arbitrary locations.
Key Weakness: The is_path_within_directory function likely checks the path string after symlink resolution, but the extraction process may create the symlink first, then write through it, bypassing the check.
Attack Scenario:
- Attacker creates a tar archive with a symlink
evil_link -> /etc/passwd. - The archive also contains a file
evil_link/overwrite(or the symlink itself is used to write data). - When ZenML extracts the archive, it creates the symlink, then writes the file through the symlink, overwriting
/etc/passwd. - This can lead to privilege escalation or arbitrary command execution.
Vulnerable vs. Patched Code
Vulnerable Code (ZenML 0.83.1):
class PathMaterializer:
def load(self, filepath: str) -> Any:
with tarfile.open(filepath, "r:gz") as tar:
for member in tar.getmembers():
# Vulnerable: does not check for symlinks/hardlinks
if not is_path_within_directory(member.name, self.working_dir):
raise ValueError("Path traversal detected")
tar.extract(member, path=self.working_dir)
Patched Code (Hypothetical):
class PathMaterializer:
def load(self, filepath: str) -> Any:
with tarfile.open(filepath, "r:gz") as tar:
for member in tar.getmembers():
# Check for symlinks and hardlinks
if member.issym() or member.islnk():
raise ValueError("Symlinks and hardlinks are not allowed")
# Resolve the path and check
resolved_path = os.path.realpath(os.path.join(self.working_dir, member.name))
if not resolved_path.startswith(os.path.realpath(self.working_dir)):
raise ValueError("Path traversal detected")
tar.extract(member, path=self.working_dir)
Exploitation & Lab Setup
Red Team
Prerequisites:
- ZenML 0.83.1 installed.
- Ability to supply a malicious
data.tar.gzfile to thePathMaterializer.load()method.
Exploit Steps:
- Create a malicious tar archive:
# Create a symlink pointing to /etc/passwd ln -s /etc/passwd evil_link # Create a tar archive containing the symlink and a file to overwrite tar -czf exploit.tar.gz evil_link # Alternatively, create a tar with a hardlink echo "malicious_content" > target_file ln target_file hardlink_to_passwd tar -czf exploit.tar.gz hardlink_to_passwd - Deliver the archive to the target system (e.g., via a ZenML pipeline step that reads from a remote source).
- Trigger the extraction by calling
PathMaterializer.load()on the archive. - The symlink/hardlink bypasses the path check, allowing overwrite of
/etc/passwdor other critical files.
Advanced Exploit:
- Overwrite
~/.ssh/authorized_keysto add an attacker's SSH key. - Overwrite a cron job or systemd service to execute arbitrary commands.
Blue Team
Detection:
- Monitor for tar archives containing symlinks or hardlinks in ZenML pipeline artifacts.
- Use file integrity monitoring (FIM) on critical system files.
- Enable auditd to log file writes to sensitive paths.
Prevention:
- Apply the hypothetical patch above.
- Use a sandboxed environment for ZenML pipeline execution (e.g., containers with read-only filesystems).
- Restrict the ZenML service account's write permissions.
Indicators of Compromise (IOCs)
File System:
- Unexpected symlinks in ZenML working directories.
- Modified system files (e.g.,
/etc/passwd,/etc/shadow,~/.ssh/authorized_keys). - Tar archives with symlink or hardlink entries in ZenML artifact storage.
Network:
- Outbound connections from the ZenML server to unknown IPs (if RCE is achieved).
Process:
- ZenML processes writing to unexpected paths (e.g.,
/etc/).
- ZenML processes writing to unexpected paths (e.g.,
Logs:
- ZenML logs showing "Path traversal detected" errors (if partial validation exists).
- Auditd logs showing writes to sensitive files by the ZenML user.
Detection Engineering
YARA Rule
rule CVE_2025_8406_ZenML_PathTraversal {
meta:
description = "Detects tar archives with symlinks or hardlinks targeting ZenML path traversal"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-8406"
strings:
$symlink = { 75 73 74 61 72 00 30 30 30 30 30 30 30 30 30 30 20 00 } // 'ustar' with symlink indicator
$hardlink = { 75 73 74 61 72 00 30 30 30 30 30 30 30 30 30 30 20 00 } // 'ustar' with hardlink indicator
condition:
any of them
}
Sigma Rule
title: CVE-2025-8406 - ZenML Path Traversal via Symlink in Tar Archive
id: 8a4b3c2d-1e5f-4a7b-9c8d-0e1f2a3b4c5d
status: experimental
description: Detects extraction of tar archives with symlinks or hardlinks by ZenML PathMaterializer
author: Valters IT
date: 2025-04-10
logsource:
category: process_creation
product: linux
detection:
selection:
Image|endswith: '/python3'
CommandLine|contains: 'tarfile'
CommandLine|contains: 'extract'
condition: selection
falsepositives:
- Legitimate use of symlinks in ZenML pipelines (rare)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-8406 - ZenML Path Traversal via Tar Archive"; flow:to_server; content:"tar"; http_client_body; content:"ustar"; distance:0; within:5; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Isolate ZenML instances from sensitive systems until a patch is available.
- Restrict write permissions for the ZenML service account to only necessary directories.
- Implement input validation on tar archives before extraction (e.g., reject archives with symlinks/hardlinks).
Long-term Fix:
- Apply the patched code (see "Vulnerable vs. Patched Code" section) or upgrade to a fixed version when released.
- Monitor the ZenML GitHub repository for official patches.
Workaround:
- Use a custom
PathMaterializersubclass that overrides theloadmethod with proper symlink/hardlink checks.
Valters IT Signature
This report was generated by Valters IT DevSecOps AI. For questions, contact security@valters-it.com.