VYPR
High severityNVD Advisory· Published Oct 20, 2023· Updated Sep 12, 2024

Trojan Lockfilein pdm

CVE-2023-45805

Description

A malicious pdm.lock file can cause PDM to install a different package than specified, enabling dependency confusion and arbitrary code execution.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A malicious pdm.lock file can cause PDM to install a different package than specified, enabling dependency confusion and arbitrary code execution.

Root

Cause

CVE-2023-45805 is a vulnerability in PDM, a Python package and dependency manager. The issue lies in how PDM validates package names and versions during dependency resolution from a pdm.lock file. Specifically, PDM may accept a version string like 2-2 for a project foo, even though PyPI would interpret that as project foo-2 version 2. This occurs because the version is only required to be parseable as a version, and the filename must be a prefix of the project name, but no verification ensures the version matches the intended package [1][2]. PEP 440 defines strict rules for version normalization, and 2-2 is not a valid normalized version per that standard [1].

Exploitation

To exploit this, an attacker could craft a malicious pdm.lock file that lists a dependency such as foo==2-2. If the attacker uploads a package with the name foo-2 and version 2 to PyPI, with a filename foo-2-2.tar.gz, PyPI will interpret it as project foo-2 version 2, but PDM will misinterpret it as project foo version 2-2. This confusion can be used by an insider or a malicious open-source project maintainer to trick users into installing a different package than intended [2]. No authentication bypass is needed; the attacker must only be able to influence the lock file or supply a malicious project.

Impact

Successful exploitation leads to dependency confusion, where the installed package differs from what is listed in pyproject.toml. This could include the installation of malicious code, potentially resulting in arbitrary code execution during the install process. The vulnerability also enables downgrade attacks by simply altering the version number in the lock file [2].

Mitigation

The vulnerability has been addressed in commit 6853e2642df, which is part of PDM version 2.9.4. Users are urged to upgrade to the latest version. No known workarounds exist [2].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
pdmPyPI
<= 2.9.3

Affected products

2
  • ghsa-coords
    Range: <= 2.9.3
  • pdm-project/pdmv5
    Range: >= 2.0.0,< 2.9.4

Patches

1
6853e2642dfa

Merge pull request from GHSA-j44v-mmf2-xvm9

https://github.com/pdm-project/pdmFrost MingOct 18, 2023via ghsa
1 file changed · +6 1
  • src/pdm/models/repositories.py+6 1 modified
    @@ -10,7 +10,7 @@
     from typing import TYPE_CHECKING, Generator, TypeVar, cast
     
     from pdm import termui
    -from pdm.exceptions import CandidateInfoNotFound, CandidateNotFound, PackageWarning
    +from pdm.exceptions import CandidateInfoNotFound, CandidateNotFound, PackageWarning, PdmException
     from pdm.models.candidates import Candidate, make_candidate
     from pdm.models.requirements import (
         Requirement,
    @@ -486,6 +486,7 @@ def all_candidates(self) -> dict[str, Candidate]:
     
         def _read_lockfile(self, lockfile: Mapping[str, Any]) -> None:
             root = self.environment.project.root
    +        static_urls = self.environment.project.lockfile.static_urls
             with cd(root):
                 for package in lockfile.get("package", []):
                     version = package.get("version")
    @@ -500,6 +501,10 @@ def _read_lockfile(self, lockfile: Mapping[str, Any]) -> None:
                         req.url = path_to_url(posixpath.join(root, req.path))  # type: ignore[attr-defined]
                     can = make_candidate(req, name=package_name, version=version)
                     can.hashes = package.get("files", [])
    +                if not static_urls and any("url" in f for f in can.hashes):
    +                    raise PdmException(
    +                        "Static URLs are not allowed in lockfile unless enabled by `pdm lock --static-urls`."
    +                    )
                     can_id = self._identify_candidate(can)
                     self.packages[can_id] = can
                     candidate_info: CandidateInfo = (
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.