CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-W75W-9QV4-J5XJ
4.0

GHSA-W75W-9QV4-J5XJ: Path Traversal in dbt-common Archive Extraction

Amit Schendel
Amit Schendel
Senior Security Researcher

Mar 5, 2026·5 min read·7 visits

PoC Available

Executive Summary (TL;DR)

dbt-common incorrectly uses string prefix matching to validate file paths during tarball extraction. Attackers can bypass this check using crafted paths (e.g., `/target_evil` vs `/target`) to write files outside the intended directory. Fixed in versions 1.34.2 and 1.37.3.

A path traversal vulnerability exists in the `dbt-common` Python package due to insecure usage of `os.path.commonprefix` during archive extraction. This flaw allows malicious tarballs to bypass directory confinement checks and write files to sibling directories of the intended destination. The vulnerability affects versions prior to 1.34.2 and versions between 1.35.0 and 1.37.3. It arises from a logic error where string prefix matching is used instead of path component comparison, effectively neutralizing the sandbox check intended to prevent arbitrary file writes.

Vulnerability Overview

The dbt-common package, a foundational library for the dbt (Data Build Tool) ecosystem, contains a path traversal vulnerability within its safe_extract() utility. This function is designed to unpack tarball archives securely by ensuring that all extracted files reside strictly within a specified target directory. However, the implementation of this boundary check was flawed due to the misuse of the Python standard library function os.path.commonprefix.

This vulnerability is technically indistinguishable from CVE-2026-1703, a similar flaw identified in the pip package manager. Both vulnerabilities stem from the misconception that commonprefix operates on path components (directories), whereas it actually operates on raw strings. This distinction allows an attacker to construct a path that matches the characters of the target directory's name but extends into a sibling directory, thereby bypassing the confinement check.

The impact is categorized as a partial integrity violation. An attacker who can convince a user to install a malicious dbt package or process a crafted tarball can write files to arbitrary locations on the disk, provided those locations share a string prefix with the intended destination or if the attacker utilizes specific traversal techniques relative to that prefix. This can lead to the overwriting of configuration files or the planting of malicious scripts in adjacent directories.

Root Cause Analysis

The root cause of this vulnerability lies in the _is_within_directory helper function located in dbt_common/clients/system.py. The function attempts to verify that a file path falls under a parent directory by comparing the common prefix of the two absolute paths. The vulnerable logic is implemented as follows:

prefix = os.path.commonprefix([abs_directory, abs_target])
return prefix == abs_directory

The Python documentation for os.path.commonprefix explicitly states that it returns the "longest string prefix," acting on a character-by-character basis. It does not respect directory separators. Consequently, if the intended destination is /usr/local/dbt/packages and the malicious path is /usr/local/dbt/packages_evil/exploit.sh, the common prefix is calculated as /usr/local/dbt/packages.

Since the calculated prefix matches the authorized abs_directory, the function returns True, erroneously confirming that the file is safe to extract. The operating system, however, treats packages and packages_evil as two distinct, sibling directories. This discrepancy between the validator's string-based logic and the filesystem's path-based logic creates the traversal primitive.

Code Analysis

The remediation involves replacing os.path.commonprefix with os.path.commonpath. Introduced in Python 3.5, commonpath correctly handles filesystem paths by returning the longest common sub-path, respecting directory separators. If paths are on different drives or do not share a common root, it raises a ValueError.

Below is the comparison of the vulnerable and patched code in dbt_common/clients/system.py:

Vulnerable Implementation:

def _is_within_directory(directory, target):
    abs_directory = os.path.abspath(directory)
    abs_target = os.path.abspath(target)
    # FLAW: Character-wise comparison ignores directory boundaries
    prefix = os.path.commonprefix([abs_directory, abs_target])
    return prefix == abs_directory

Patched Implementation (Commit e547954):

def _is_within_directory(directory, target):
    abs_directory = os.path.abspath(directory)
    abs_target = os.path.abspath(target)
    try:
        # FIX: Component-wise comparison respects directory boundaries
        prefix = os.path.commonpath([abs_directory, abs_target])
        return prefix == abs_directory
    except ValueError:
        # Handles cases like different drives on Windows
        return False

In the patched version, comparing /tmp/pkg and /tmp/pkgevil using commonpath returns /tmp. Since /tmp does not equal /tmp/pkg, the check fails (False), and the extraction is aborted, preventing the traversal.

Exploitation Mechanics

To exploit this vulnerability, an attacker must craft a malicious tarball (.tar.gz) containing file entries with manipulated paths. The exploit relies on the fact that dbt packages are often installed via URLs or Git repositories, which dbt-common processes.

The attack flow is as follows:

  1. Preparation: The attacker determines the likely extraction path or relies on the relative path behavior. They create a tarball where a file entry points to a sibling directory of the expected destination.
  2. Path Construction: If the target directory is .../dbt_packages/target, the attacker names the file inside the archive ../target_suffix/malicious_file. When resolved absolutely, if the prefix matches, the check passes.
  3. Delivery: The attacker hosts this tarball or publishes a package containing it.
  4. Execution: The victim runs dbt deps or installs the package. The untar_package function invokes _is_within_directory, which returns True for the malicious path.

The accompanying Proof-of-Concept (PoC) from the unit tests demonstrates this explicitly:

# Creating a malicious path that is a sibling with a shared prefix
sibling_path = "../" + os.path.basename(self.tempdest) + "evil/malicious.txt"
with tarfile.open(fileobj=named_tar_file, mode="w:gz") as tar:
    tar.addfile(tarfile.TarInfo(sibling_path), open(file_a.name))

When this archive is extracted against self.tempdest, the file is written to self.tempdest + "evil", successfully escaping the sandbox.

Impact Assessment

The impact of this vulnerability is classified as Medium (CVSS 4.0 Score: 4.0). While it allows for arbitrary file writes, several mitigating factors limit the severity compared to a critical Remote Code Execution (RCE) flaw.

CVSS Vector: CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

  • User Interaction (UI:A): The victim must actively install a malicious package or process a tainted file.
  • Attack Requirements (AT:P): The attack is not unconditional; the attacker must craft a package that mimics the prefix of the destination directory.
  • Integrity (VI:L): The primary impact is the ability to write files to unintended locations. This could lead to code execution if the attacker can overwrite a script, configuration file, or binary that is subsequently executed by the user or system, but this is a secondary effect.

Despite the "Medium" rating, in automated CI/CD environments where dbt runs might occur with elevated privileges or where the filesystem is shared across pipeline stages, this could facilitate lateral movement or persistence.

Official Patches

dbt LabsOfficial patch commit for dbt-common
GitHub AdvisoryOfficial GitHub Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
4.0/ 10
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

Affected Systems

dbt-common Python packagedbt-core (via dependency)Systems executing `dbt deps` or `dbt package install` from untrusted sources

Affected Versions Detail

Product
Affected Versions
Fixed Version
dbt-common
dbt Labs
< 1.34.21.34.2
dbt-common
dbt Labs
>= 1.35.0, < 1.37.31.37.3
AttributeDetail
CWE IDCWE-22
CWE NameImproper Limitation of a Pathname to a Restricted Directory
CVSS Score4.0 (Medium)
CVSS VectorCVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
Exploit MaturityProof of Concept (PoC)
Patch StatusAvailable (1.34.2, 1.37.3)

MITRE ATT&CK Mapping

T1204.002User Execution: Malicious File
Execution
T1059Command and Scripting Interpreter
Execution
CWE-22
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

Known Exploits & Detection

GitHub (Unit Test)Reproduction test case 'test_untar_package_sibling_path_traversal' demonstrating the bypass.

Vulnerability Timeline

Vulnerability identified and internal report created
2026-02-25
Fix commit pushed to dbt-common repository
2026-02-27
GHSA-W75W-9QV4-J5XJ published
2026-03-05

References & Sources

  • [1]GHSA-W75W-9QV4-J5XJ
  • [2]Related CVE-2026-1703 (pip)
  • [3]Python os.path.commonpath Documentation
Related Vulnerabilities
CVE-2026-1703

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.