Skip to content

DDEV incomplete tar symlink traversal fix allows host file overwrite - Incomplete fix of CVE-2026-32885

High severity GitHub Reviewed Published Sep 2, 2026 in ddev/ddev • Updated Nov 9, 2026

Package

gomod github.com/ddev/ddev (Go)

Affected versions

< 1.25.4

Patched versions

1.25.4

Description

Summary

The CVE-2026-32885 ZipSlip fix added a symlink-target escape check to Untar, but the check rebases an ABSOLUTE symlink target into dest before validating (filepath.Join(dest, "/etc") stays lexically inside dest and passes), while the symlink is then created with the RAW absolute target via os.Symlink(file.Linkname, ...), so a malicious archive plants a host-absolute symlink and a following regular-file entry writes through it, restoring arbitrary host file create/overwrite (reaching $HOME rc-files, hence RCE). Confirmed at HEAD.

The defect (the symlink check is a no-op for absolute targets)

CVE-2026-32885 (fixed v1.25.2, commit 05cbe299) added a lexical containment check on the entry path and a NEW symlink-target validation. pkg/archive/archive.go, Untar, tar.TypeSymlink case:

if filepath.IsAbs(file.Linkname) {
    resolvedTarget = filepath.Join(dest, file.Linkname)   // line 298: absolute target REBASED into dest
} else {
    resolvedTarget = filepath.Join(fullPathDir, file.Linkname)
}
if !strings.HasPrefix(filepath.Clean(resolvedTarget)+sep, filepath.Clean(dest)+sep) {  // line 302
    return ...escapes destination...                       // line 303
}
_ = os.Remove(fullPath)                                     // line 307
err = os.Symlink(file.Linkname, fullPath)                  // line 310: writes the RAW Linkname

For an absolute Linkname like /Users/victim, line 298 computes filepath.Join(dest, "/Users/victim") = dest/Users/victim (lexically inside dest), so the escape check at line 302 PASSES. But line 310 creates the symlink with the raw file.Linkname, so the on-disk symlink dest/link points at the real host path /Users/victim. The value validated (rebased) is not the value written (raw): a check-one-thing / do-another divergence.

Write-through: the archive carries a second regular-file entry whose Name traverses the planted link (e.g. link/.zshrc). Its fullPath is lexically inside dest so the line-238 check passes (that check is purely lexical and does not resolve the symlink), then os.Create follows the planted symlink and overwrites /Users/victim/.zshrc on the host. Overwriting a shell rc-file, git hook, or cron entry yields code execution. Reachable via ddev add-on get <repo|url> (the exact remote-add-on vector the advisory names), and via ddev import-db / import-files. GitHub codeload tarballs preserve symlinks.

Verification

EXECUTED (go test driving the real Untar): a file was written OUTSIDE dest and Untar returned nil (VULNERABLE); a pre-existing host file was truncated and overwritten with the attacker payload; the negative controls (a relative ../ symlink escape, and a plain ../ file entry) are both correctly rejected, isolating the bug to the absolute-symlink branch. NOT verified: the end-to-end add-on get over the network (the caller chain is source-confirmed); Windows (reliable on macOS/Linux, DDEV's primary hosts). Unzip is NOT affected (tar-only).

Suggested fix

Reject absolute symlink targets outright (a dev-environment archive has no need to plant host-absolute symlinks), or validate the RAW target that will actually be written rather than a rebased copy. Additionally, resolve symlinks when validating each regular-file entry's parent so a write cannot traverse a previously-planted link (or extract to a staging dir and reject any entry whose realpath escapes). The lexical line-238 check does not defend against a planted symlink.

Tooling

AI assistance was used while investigating. The write-through is executed-verified with negative controls (an absolute-symlink entry plus a follow-up file entry wrote and overwrote files OUTSIDE dest while relative-escape and plain-ZipSlip controls were correctly rejected), and I confirmed at HEAD that Untar rebases an absolute symlink target into dest for the escape check (line 298) but creates the symlink with the raw absolute target (line 310).

References

@stasadev stasadev published to ddev/ddev Sep 2, 2026
Published by the National Vulnerability Database Nov 6, 2026
Published to the GitHub Advisory Database Nov 9, 2026
Reviewed Nov 9, 2026
Last updated Nov 9, 2026

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

EPSS score

Exploit Prediction Scoring System (EPSS)

This score estimates the probability of this vulnerability being exploited within the next 30 days. Data provided by FIRST.
(24th percentile)

Weaknesses

Improper Limitation of a Pathname to a Restricted Directory

The product 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 product 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. Learn more on MITRE.

Improper Link Resolution Before File Access

The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource. Learn more on MITRE.

CVE ID

CVE-2026-108262

GHSA ID

GHSA-9hq4-hm3j-jmph

Source code

Credits

Loading Checking history
See something to contribute? Suggest improvements for this vulnerability.