{"success":true,"data":{"threats":[{"id":"f80f0281-2f05-4e43-98c1-8c47e85875d6","slug":"ghsa-8w8g-wq8h-fq33","externalId":"GHSA-8w8g-wq8h-fq33","source":"OSV","sourceType":"ghsa","type":"vulnerability","title":"Dulwich: Symlink write-through in checkout(paths=[]) via raw os.open bypasses all symlink protections","description":"## Summary\n\nDulwich's `porcelain.checkout(paths=[...])` code path writes files using raw `os.open(file_path, O_WRONLY|O_CREAT|O_TRUNC, mode)` followed by `f.write(obj.data)`. This code path does NOT call `build_file_from_blob()` at all, completely bypassing any symlink protections (including the unreleased d09f8af fix). `os.open` without `O_NOFOLLOW` follows symlinks at both the target file and intermediate directories, allowing arbitrary file writes.\n\n## Root Cause\n\nAt `dulwich/porcelain/__init__.py:5661-5675`, the `checkout(paths=[...])` implementation:\n\n```python\nfile_path = _checked_worktree_path(r, path)\nos.makedirs(os.path.dirname(file_path), exist_ok=True)\nflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC\nwith os.fdopen(os.open(file_path, flags, mode), \"wb\") as f:\n    f.write(obj.data)\n```\n\n`_checked_worktree_path()` (line 601-631) only performs name validation — checking that the path doesn't start with `/` or `\\\\` and that components pass `INVALID_DOTNAMES` checks. It performs zero filesystem symlink detection.\n\n## Impact\n\nAn attacker can craft a malicious repository that, when a victim clones it and runs `checkout(paths=[...])`, writes attacker-controlled content (with attacker-controlled permissions) to any filesystem location accessible to the user. Writing to `.git/hooks/post-checkout` achieves RCE on the next git checkout.\n\n## Attack Scenario\n\n1. Attacker creates a repository where HEAD has `trigger` as a symlink (mode 120000, content `../../.git/hooks/post-checkout`), and tag `v1.0` has `trigger` as an executable file (mode 100755, content `#!/bin/sh\\nmalicious_payload`)\n2. Victim clones the repository — worktree has `trigger` → `../../.git/hooks/post-checkout` (a symlink)\n3. Victim runs `porcelain.checkout(repo, target=\"v1.0\", paths=[\"trigger\"])` to restore a specific file from a tag\n4. `_checked_worktree_path(r, \"trigger\")` passes — name validation only, no symlink check\n5. `os.open(\"trigger\", O_WRONLY|O_CREAT|O_TRUNC, 0o755)` follows the symlink → opens `.git/hooks/post-checkout` for writing\n6. `f.write(obj.data)` writes the malicious payload to the hook\n7. Next checkout operation triggers the hook → RCE\n\n## Suggested Fix\n\nReplace the raw `os.open` path with a call to `build_file_from_blob` (once that function is hardened against intermediate symlinks), or add explicit symlink detection: resolve the path with `os.path.realpath()` and verify it stays within the worktree root before opening.\n\nReported by **zx (Jace)**","cveId":null,"cvssScore":null,"cvssVector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H","severity":"high","vendor":"PyPI","product":"dulwich","affectedVersions":["pkg:pypi/dulwich >= 0.24.0, < 1.2.8"],"cwes":["CWE-59","CWE-61"],"tags":["osv","osv:ghsa-8w8g-wq8h-fq33","ecosystem:pypi"],"relatedCves":[],"titleFingerprint":null,"countryCodes":[],"knownExploited":false,"patchAvailable":false,"patchLinks":[],"references":[{"url":"https://osv.dev/vulnerability/GHSA-8w8g-wq8h-fq33","type":"advisory","title":"OSV GHSA-8w8g-wq8h-fq33"},{"url":"https://github.com/jelmer/dulwich/security/advisories/GHSA-8w8g-wq8h-fq33","type":"other","title":"OSV web"},{"url":"https://github.com/jelmer/dulwich/commit/9389fcb5cb9113adfc7f207d8be86a56904db3e8","type":"other","title":"OSV web"},{"url":"https://github.com/jelmer/dulwich","type":"vendor","title":"OSV package"},{"url":"https://github.com/jelmer/dulwich/releases/tag/dulwich-1.2.8","type":"other","title":"OSV web"}],"epssScore":null,"epssPercentile":null,"nucleiTemplatePath":null,"nucleiSeverity":null,"enrichment":null,"publishedAt":"2026-10-02T18:53:35.000Z","addedAt":"2026-10-02T19:54:22.609Z","updatedAt":"2026-10-02T19:54:22.609Z","epssUpdatedAt":null,"nucleiUpdatedAt":null,"links":[{"label":"GitHub Advisory","url":"https://github.com/advisories/GHSA-8w8g-wq8h-fq33"},{"label":"OSV","url":"https://osv.dev/vulnerability/GHSA-8w8g-wq8h-fq33"}]}],"pagination":{"page":1,"limit":20,"total":1,"totalPages":1,"hasNext":false,"hasPrev":false}},"meta":{"apiVersion":"v1","requestedAt":"2026-10-09T01:19:16.675Z","durationMs":7,"filters":{"search":null,"severity":[],"type":[],"country":[],"tag":["osv:ghsa-8w8g-wq8h-fq33"],"cwe":[],"vendor":null,"product":null,"cve":null,"source":[],"days":null,"publishedAfter":null,"publishedBefore":null,"minCvss":null,"maxCvss":null,"minEpss":null,"knownExploited":null,"hasPatch":null,"hasNucleiTemplate":null},"sort":"newest","unknownParams":[],"warnings":[]}}