Skip to main content

PDM CVE-2026-47763

MEDIUM
UNIX Symbolic Link (Symlink) Following (CWE-61)
2026-06-10 https://github.com/pdm-project/pdm GHSA-ghq2-5c67-fprm
Share

Severity by source

vuln.today AI
6.1 MEDIUM

Local vector and required user interaction reflect that victim must run PDM against an attacker-controlled checkout; PR:N because attacker needs no system privileges, only a shared repository; no confidentiality impact as only a write primitive is demonstrated.

3.1 AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L
SUSE
MEDIUM
qualitative

Estimated by vuln.today — no official severity rating has been published for this CVE yet.

Lifecycle Timeline

2
Source Code Evidence Fetched
Jun 10, 2026 - 21:22 vuln.today
Analysis Generated
Jun 10, 2026 - 21:22 vuln.today

DescriptionCVE.org

Summary

PDM writes several project-local state or configuration files without symlink protection. If a malicious repository places those files as symlinks, local PDM operations can overwrite the symlink targets.

This creates an arbitrary file clobber primitive relative to the privileges of the invoking user.

Affected Behavior

  • Project-local config writes can affect files outside the repository
  • The most stable demonstrated sink is pdm.toml
  • Related sinks include .pdm-python and .python-version

Affected Code

  • src/pdm/project/config.py:303-350
  • src/pdm/project/core.py:209-217
  • src/pdm/cli/commands/use.py:187-189

Technical Details

Config.__init__() resolves the project-local pdm.toml path and _save_config() writes to the resolved target. If PROJECT_ROOT/pdm.toml is a symlink to another file, pdm config -l ... updates the target file instead of refusing the write.

The same general problem exists for other project-local persistence paths that are written directly with no lstat / O_NOFOLLOW protection.

For the pdm.toml PoC specifically, the target file must already contain parseable TOML. Otherwise the load step fails before the write path is reached. That parser constraint does not apply to the .pdm-python or .python-version sinks.

Impact

  • Arbitrary file clobber as the invoking user
  • Destructive modification of local files outside the repository root
  • Useful primitive for privilege abuse when pdm is run in elevated contexts

Reproduction

PoC:

bash
# Replace this with a Python interpreter that can run `python -m pdm`.
PDM_PY=/path/to/python-with-pdm
tmpdir=$(mktemp -d)
target="$tmpdir/clobbered-target.toml"

cat > "$target" <<'EOF'
[seed]
value = 1
EOF

ln -s "$target" "$tmpdir/pdm.toml"

cat > "$tmpdir/pyproject.toml" <<'EOF'
[project]
name = "symlink-clobber-demo"
version = "0.0.1"
EOF

(
  cd "$tmpdir" &&
  "$PDM_PY" -m pdm config -l venv.in_project false
)

cat "$target"

Expected result:

  • A temporary project is created
  • pdm.toml is a symlink to another TOML file
  • Running pdm config -l venv.in_project false modifies the symlink target

Observed output from local validation:

text
--- target ---
[seed]
value = 1

[venv]
in_project = false

Severity

Medium

CVSS v4.0

  • Base score: 6.8 (Medium)
  • Vector: CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N

Rationale:

  • AV:L: exploitation requires local execution of pdm against an attacker-prepared checkout
  • AC:L: there is no complex constraint once the symlink sink exists
  • AT:N: no extra prerequisite beyond the victim running the relevant command is required
  • PR:N: the attacker does not need prior privileges on the victim system
  • UI:A: the victim must actively run a command that writes project-local state or config
  • VC:N: the demonstrated issue is a write primitive, not a direct read primitive
  • VI:H: the attacker can cause unauthorized modification of files outside the repository root
  • VA:L: file clobber can disrupt local operation, but direct same-step availability impact is lower than a full RCE
  • SC:N/SI:N/SA:N: the base score is limited to the directly affected system

Root Cause

Project-local file sinks are treated as trusted regular files and are written without symlink checks or guarded atomic replacement.

Recommended Remediation

  • Refuse to write project-local config/state files when the destination is a symlink
  • Use lstat and O_NOFOLLOW where available
  • Avoid resolving attacker-controlled project-local paths before writing
  • Use atomic temp-file replacement only after confirming the destination is a regular file

Disclosure Notes

This issue is independent from the code-execution issues above. It is best tracked as a separate CVE candidate because the root cause and remediation are different.

AnalysisAI

Arbitrary file clobber in PDM (Python Development Master) below version 2.27.0 allows an attacker who controls a cloned project repository to overwrite files outside the repository root by planting symlinks at project-local config paths (pdm.toml, .pdm-python, .python-version) that PDM writes to without symlink protection. When a developer runs any PDM command triggering a project-local config write against the malicious checkout, the tool follows the symlink and overwrites the target with attacker-influenced content - up to arbitrary file corruption relative to the invoking user's privileges. A working proof-of-concept is included in the GitHub security advisory GHSA-ghq2-5c67-fprm; no active exploitation is confirmed in CISA KEV at time of analysis.

Technical ContextAI

PDM is a Python package and dependency manager distributed via pip (pkg:pip/pdm). The root cause is CWE-61 (UNIX Symbolic Link Following): project-local file sinks - specifically pdm.toml (handled in src/pdm/project/config.py:303-350 via Config.__init__() and _save_config()), .pdm-python (src/pdm/project/core.py:209-217), and .python-version (src/pdm/cli/commands/use.py:187-189) - are treated as trusted regular files. PDM resolves these paths and writes to the resolved destination without first calling lstat() to verify the path is not a symlink, and without using O_NOFOLLOW or atomic temp-file replacement guarded by a regular-file check. For the pdm.toml sink, an additional constraint exists: the symlink target must contain parseable TOML for the load step to succeed before the write path is reached. This constraint does not apply to .pdm-python or .python-version, making those sinks more reliably exploitable. The vulnerability is classified under CWE-61 and is architecturally equivalent to well-known TOCTOU symlink-following bugs in Unix tooling.

RemediationAI

Upgrade PDM to version 2.27.0 or later; this is the vendor-released patch that explicitly refuses to write project-local config and state files (pdm.toml, .pdm-python, .python-version) when the destination is a symlink. The fix is confirmed in the release notes at https://github.com/pdm-project/pdm/releases/tag/2.27.0 (issue #3788) and the security advisory GHSA-ghq2-5c67-fprm at https://github.com/pdm-project/pdm/security/advisories/GHSA-ghq2-5c67-fprm. For environments where immediate upgrade is not possible, the primary compensating control is to avoid running PDM commands (especially pdm config -l or pdm use) inside untrusted or externally-sourced repository checkouts. In CI/CD pipelines running PDM with elevated privileges, restrict which repositories are checked out and ensure workspace directories are freshly initialized rather than reused across builds, which eliminates the attacker's ability to pre-place symlinks. Note that these workarounds are operationally constraining and do not address the root cause - upgrading to 2.27.0 is strongly preferred.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2026-55255 HIGH POC
8.4 Jun 19

Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing

Vendor StatusVendor

SUSE

Severity: Moderate
Product Status
openSUSE Tumbleweed Fixed

Share

CVE-2026-47763 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy