CWE-61
AllowedUNIX Symbolic Link (Symlink) Following
Abstraction: Compound · Status: Incomplete
The product, when opening a file or directory, does not sufficiently account for when the file is a symbolic link that resolves to a target outside of the intended control sphere. This could allow an attacker to cause the product to operate on unauthorized files.
301 vulnerabilities reference this CWE, most recent first.
GHSA-F794-5JV7-7672
Vulnerability from github – Published: 2026-09-02 14:35 – Updated: 2026-09-02 14:35Summary
NLTK's downloader now blocks symlink escapes during ZIP extraction, but it still treats pre-existing hardlinks inside the install tree as ordinary in-root files. A normal package install can therefore overwrite an outside-root inode through that hardlink.
Details
- Vulnerability type: Filesystem containment bypass
- Affected component:
nltk.downloader.Downloader.download,nltk.downloader.Downloader.incr_download - Affected versions: Published
3.9.4and current sourcev3.10.0-rc2both reproduced for the extraction-stage overwrite. - Patched versions: 3.10.3
- Root cause: The downloader validates traversal and symlink conditions but does not reject pre-existing hardlink aliases inside the install tree.
The install flow correctly rejects a pre-existing symlink at an extraction target, yet it accepts a pre-existing hardlink at the same path. When the package is installed, extracted member data is written through the hardlink and mutates the outside inode.
PoC
Preconditions - The attacker can plant files inside a writable shared downloader root on the same filesystem as the target file.
Steps
1. Prepare a downloader root and create a hardlink inside it that points to an outside target file.
2. Confirm a symlink at the same path is rejected as a negative control.
3. Run a normal Downloader.download() package install whose extracted member lands on the hardlink path.
4. Observe the outside target file is overwritten while the downloader still reports the package as installed.
Minimal reproducible excerpt
extract_hardlink_before ORIGINAL
extract_hardlink_after PWNED
extract_hardlink_status installed
Impact
A shared or attacker-influenced downloader directory can be turned into an overwrite primitive against same-filesystem files outside the intended install root.
Remediation
Treat pre-existing hardlinks as unsafe in extraction targets, verify that each write path stays within the intended install tree at the inode level, and add regression tests that pair hardlinks with existing symlink controls.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.10.2"
},
"package": {
"ecosystem": "PyPI",
"name": "nltk"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.10.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-81727"
],
"database_specific": {
"cwe_ids": [
"CWE-59",
"CWE-61",
"CWE-73"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-02T14:35:41Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\n\nNLTK\u0027s downloader now blocks symlink escapes during ZIP extraction, but it still treats pre-existing hardlinks inside the install tree as ordinary in-root files. A normal package install can therefore overwrite an outside-root inode through that hardlink.\n\n### Details\n\n- **Vulnerability type:** Filesystem containment bypass\n- **Affected component:** `nltk.downloader.Downloader.download`, `nltk.downloader.Downloader.incr_download`\n- **Affected versions:** Published `3.9.4` and current source `v3.10.0-rc2` both reproduced for the extraction-stage overwrite.\n- **Patched versions:** 3.10.3\n- **Root cause:** The downloader validates traversal and symlink conditions but does not reject pre-existing hardlink aliases inside the install tree.\n\nThe install flow correctly rejects a pre-existing symlink at an extraction target, yet it accepts a pre-existing hardlink at the same path. When the package is installed, extracted member data is written through the hardlink and mutates the outside inode.\n\n### PoC\n\n**Preconditions**\n- The attacker can plant files inside a writable shared downloader root on the same filesystem as the target file.\n\n**Steps**\n1. Prepare a downloader root and create a hardlink inside it that points to an outside target file.\n2. Confirm a symlink at the same path is rejected as a negative control.\n3. Run a normal `Downloader.download()` package install whose extracted member lands on the hardlink path.\n4. Observe the outside target file is overwritten while the downloader still reports the package as installed.\n\n**Minimal reproducible excerpt**\n\n```text\nextract_hardlink_before ORIGINAL\nextract_hardlink_after PWNED\nextract_hardlink_status installed\n```\n\n### Impact\n\nA shared or attacker-influenced downloader directory can be turned into an overwrite primitive against same-filesystem files outside the intended install root.\n\n### Remediation\n\nTreat pre-existing hardlinks as unsafe in extraction targets, verify that each write path stays within the intended install tree at the inode level, and add regression tests that pair hardlinks with existing symlink controls.",
"id": "GHSA-f794-5jv7-7672",
"modified": "2026-09-02T14:35:41Z",
"published": "2026-09-02T14:35:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nltk/nltk/security/advisories/GHSA-f794-5jv7-7672"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-81727"
},
{
"type": "WEB",
"url": "https://github.com/nltk/nltk/pull/3797"
},
{
"type": "WEB",
"url": "https://github.com/nltk/nltk/commit/9e6d5f05902b9aaa1221a0a565448d17a9c9b3e8"
},
{
"type": "PACKAGE",
"url": "https://github.com/nltk/nltk"
},
{
"type": "WEB",
"url": "https://github.com/nltk/nltk/releases/tag/v3.10.3"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/nltk/PYSEC-2026-3741.yaml"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/nltk-before-3.10.3-hardlink-file-overwrite-via-downloader"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "NLTK: Downloader.download follows hardlinks and overwrites outside-root files"
}
GHSA-FV94-QVG8-XQPW
Vulnerability from github – Published: 2026-04-02 21:23 – Updated: 2026-05-06 19:11Summary
SSH sandbox tar upload follows symlinks, enabling arbitrary file write on remote host
Current Maintainer Triage
- Status: open
- Normalized severity: high
- Assessment: Real in shipped v2026.3.28: SSH sandbox tar upload lacked pre-upload symlink escape rejection until 3d5af14984 on 2026-03-31; maintainers already accepted it and the fix is unreleased.
Affected Packages / Versions
- Package:
openclaw(npm) - Latest published npm version:
2026.3.31 - Vulnerable version range:
<=2026.3.28 - Patched versions:
>= 2026.3.31 - First stable tag containing the fix:
v2026.3.31
Fix Commit(s)
3d5af14984ac1976c747a8e11581d697bd0829dc— 2026-03-31T19:56:45+09:00
OpenClaw thanks @AntAISecurityLab for reporting.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2026.3.28"
},
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.3.31"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41364"
],
"database_specific": {
"cwe_ids": [
"CWE-59",
"CWE-61"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-02T21:23:32Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\nSSH sandbox tar upload follows symlinks, enabling arbitrary file write on remote host\n\n## Current Maintainer Triage\n- Status: open\n- Normalized severity: high\n- Assessment: Real in shipped v2026.3.28: SSH sandbox tar upload lacked pre-upload symlink escape rejection until 3d5af14984 on 2026-03-31; maintainers already accepted it and the fix is unreleased.\n\n## Affected Packages / Versions\n- Package: `openclaw` (npm)\n- Latest published npm version: `2026.3.31`\n- Vulnerable version range: `\u003c=2026.3.28`\n- Patched versions: `\u003e= 2026.3.31`\n- First stable tag containing the fix: `v2026.3.31`\n\n## Fix Commit(s)\n- `3d5af14984ac1976c747a8e11581d697bd0829dc` \u2014 2026-03-31T19:56:45+09:00\n\nOpenClaw thanks @AntAISecurityLab for reporting.",
"id": "GHSA-fv94-qvg8-xqpw",
"modified": "2026-05-06T19:11:31Z",
"published": "2026-04-02T21:23:32Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-fv94-qvg8-xqpw"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41364"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/3d5af14984ac1976c747a8e11581d697bd0829dc"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/releases/tag/v2026.3.31"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/openclaw-arbitrary-file-write-via-symlink-following-in-ssh-sandbox-tar-upload"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenClaw: SSH sandbox tar upload follows symlinks, enabling arbitrary file write on remote host"
}
GHSA-G2WF-V8Q9-85JJ
Vulnerability from github – Published: 2022-05-24 19:07 – Updated: 2022-08-06 00:00Absolute Path Traversal vulnerability in FileviewDoc in QSAN Storage Manager allows remote authenticated attackers access arbitrary files by injecting the Symbolic Link following the Url path parameter.
{
"affected": [],
"aliases": [
"CVE-2021-32509"
],
"database_specific": {
"cwe_ids": [
"CWE-59",
"CWE-61"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-07-07T14:15:00Z",
"severity": "MODERATE"
},
"details": "Absolute Path Traversal vulnerability in FileviewDoc in QSAN Storage Manager allows remote authenticated attackers access arbitrary files by injecting the Symbolic Link following the Url path parameter.",
"id": "GHSA-g2wf-v8q9-85jj",
"modified": "2022-08-06T00:00:52Z",
"published": "2022-05-24T19:07:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-32509"
},
{
"type": "WEB",
"url": "https://www.twcert.org.tw/tw/cp-132-4865-0c967-1.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-G6QJ-9F49-6C8C
Vulnerability from github – Published: 2025-04-03 09:32 – Updated: 2025-04-03 09:32UNIX symbolic link (Symlink) following issue exists in FutureNet NXR series, VXR series and WXR series routers. Attaching to the affected product an external storage containing malicious symbolic link files, a logged-in administrative user may obtain and/or destroy internal files.
{
"affected": [],
"aliases": [
"CVE-2025-30485"
],
"database_specific": {
"cwe_ids": [
"CWE-61"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-04-03T07:15:41Z",
"severity": "MODERATE"
},
"details": "UNIX symbolic link (Symlink) following issue exists in FutureNet NXR series, VXR series and WXR series routers. Attaching to the affected product an external storage containing malicious symbolic link files, a logged-in administrative user may obtain and/or destroy internal files.",
"id": "GHSA-g6qj-9f49-6c8c",
"modified": "2025-04-03T09:32:14Z",
"published": "2025-04-03T09:32:14Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-30485"
},
{
"type": "WEB",
"url": "https://jvn.jp/en/vu/JVNVU92821536"
},
{
"type": "WEB",
"url": "https://www.centurysys.co.jp/backnumber/common/jvnvu92821536.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:P/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-G7VG-VFVV-MR49
Vulnerability from github – Published: 2026-03-10 18:31 – Updated: 2026-03-10 18:31A UNIX symbolic link (Symlink) following vulnerability in Fortinet FortiClientLinux 7.4.0 through 7.4.4, FortiClientLinux 7.2.2 through 7.2.12 may allow a local and unprivileged user to escalate their privileges to root.
{
"affected": [],
"aliases": [
"CVE-2026-24018"
],
"database_specific": {
"cwe_ids": [
"CWE-61"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-03-10T18:18:17Z",
"severity": "HIGH"
},
"details": "A UNIX symbolic link (Symlink) following vulnerability in Fortinet FortiClientLinux 7.4.0 through 7.4.4, FortiClientLinux 7.2.2 through 7.2.12 may allow a local and unprivileged user to escalate their privileges to root.",
"id": "GHSA-g7vg-vfvv-mr49",
"modified": "2026-03-10T18:31:20Z",
"published": "2026-03-10T18:31:20Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-24018"
},
{
"type": "WEB",
"url": "https://fortiguard.fortinet.com/psirt/FG-IR-26-083"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-GCMX-RFRG-443V
Vulnerability from github – Published: 2026-08-25 12:31 – Updated: 2026-08-25 12:31UNIX symbolic link (symlink) following vulnerability in ilya-zlobintsev/LACT allows for local denial-of-service. This issue affects LACT: through 0.10.0.
{
"affected": [],
"aliases": [
"CVE-2026-75038"
],
"database_specific": {
"cwe_ids": [
"CWE-61"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-25T10:18:13Z",
"severity": "MODERATE"
},
"details": "UNIX symbolic link (symlink) following vulnerability in ilya-zlobintsev/LACT allows for local denial-of-service.\u00a0This issue affects LACT: through 0.10.0.",
"id": "GHSA-gcmx-rfrg-443v",
"modified": "2026-08-25T12:31:22Z",
"published": "2026-08-25T12:31:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-75038"
},
{
"type": "WEB",
"url": "https://bugzilla.suse.com/show_bug.cgi?id=1276481"
},
{
"type": "WEB",
"url": "https://github.com/ilya-zlobintsev/LACT"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-GF79-FRWR-2V77
Vulnerability from github – Published: 2025-02-13 18:32 – Updated: 2025-02-13 18:32Dell SupportAssist OS Recovery versions prior to 5.5.13.1 contain a symbolic link attack vulnerability. A low-privileged attacker with local access could potentially exploit this vulnerability, leading to arbitrary file deletion and Elevation of Privileges.
{
"affected": [],
"aliases": [
"CVE-2025-22480"
],
"database_specific": {
"cwe_ids": [
"CWE-59",
"CWE-61"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-02-13T16:16:48Z",
"severity": "HIGH"
},
"details": "Dell SupportAssist OS Recovery versions prior to 5.5.13.1 contain a symbolic link attack vulnerability. A low-privileged attacker with local access could potentially exploit this vulnerability, leading to arbitrary file deletion and Elevation of Privileges.",
"id": "GHSA-gf79-frwr-2v77",
"modified": "2025-02-13T18:32:34Z",
"published": "2025-02-13T18:32:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-22480"
},
{
"type": "WEB",
"url": "https://www.dell.com/support/kbdoc/en-us/000275712/dsa-2025-051"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-GGJM-F3G4-RWMM
Vulnerability from github – Published: 2025-08-20 19:09 – Updated: 2025-08-21 04:07Impact
A symlink traversal vulnerability was discovered in the Read/Write File node in n8n. While the node attempts to restrict access to sensitive directories and files, it does not properly account for symbolic links (symlinks). An attacker with the ability to create symlinks—such as by using the Execute Command node—could exploit this to bypass the intended directory restrictions and read from or write to otherwise inaccessible paths. Users of n8n.cloud are not impacted.
Patches
Affected users should update to version 1.106.0 or later.
Workarounds
Until the patch is applied:
- Disable or restrict access to the
Execute Commandnode and any other nodes that allow arbitrary file system access. - Avoid using the
Read/Write Filenode on untrusted paths or inputs that could be manipulated via symlinks.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "n8n"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.106.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-57749"
],
"database_specific": {
"cwe_ids": [
"CWE-59",
"CWE-61"
],
"github_reviewed": true,
"github_reviewed_at": "2025-08-20T19:09:55Z",
"nvd_published_at": "2025-08-20T22:15:29Z",
"severity": "MODERATE"
},
"details": "### Impact\nA symlink traversal vulnerability was discovered in the `Read/Write File` node in n8n. While the node attempts to restrict access to sensitive directories and files, it does not properly account for symbolic links (symlinks). An attacker with the ability to create symlinks\u2014such as by using the `Execute Command` node\u2014could exploit this to bypass the intended directory restrictions and read from or write to otherwise inaccessible paths. Users of _n8n.cloud_ are not impacted.\n\n### Patches\nAffected users should update to version 1.106.0 or later.\n\n### Workarounds\nUntil the patch is applied:\n\n- Disable or restrict access to the `Execute Command` node and any other nodes that allow arbitrary file system access.\n- Avoid using the `Read/Write File` node on untrusted paths or inputs that could be manipulated via symlinks.",
"id": "GHSA-ggjm-f3g4-rwmm",
"modified": "2025-08-21T04:07:03Z",
"published": "2025-08-20T19:09:55Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/n8n-io/n8n/security/advisories/GHSA-ggjm-f3g4-rwmm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-57749"
},
{
"type": "WEB",
"url": "https://github.com/n8n-io/n8n/pull/17735"
},
{
"type": "WEB",
"url": "https://github.com/n8n-io/n8n/commit/c2c3e08cdf33570d9051e659812cbfbdd3c077fd"
},
{
"type": "PACKAGE",
"url": "https://github.com/n8n-io/n8n"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "n8n symlink traversal vulnerability in \"Read/Write File\" node allows access to restricted files"
}
GHSA-GHQ2-5C67-FPRM
Vulnerability from github – Published: 2026-06-10 20:32 – Updated: 2026-06-10 20:32Summary
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-pythonand.python-version
Affected Code
src/pdm/project/config.py:303-350src/pdm/project/core.py:209-217src/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
pdmis run in elevated contexts
Reproduction
PoC:
# 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.tomlis a symlink to another TOML file- Running
pdm config -l venv.in_project falsemodifies the symlink target
Observed output from local validation:
--- 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 ofpdmagainst an attacker-prepared checkoutAC:L: there is no complex constraint once the symlink sink existsAT:N: no extra prerequisite beyond the victim running the relevant command is requiredPR:N: the attacker does not need prior privileges on the victim systemUI:A: the victim must actively run a command that writes project-local state or configVC:N: the demonstrated issue is a write primitive, not a direct read primitiveVI:H: the attacker can cause unauthorized modification of files outside the repository rootVA:L: file clobber can disrupt local operation, but direct same-step availability impact is lower than a full RCESC: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
lstatandO_NOFOLLOWwhere 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.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "pdm"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.27.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-47763"
],
"database_specific": {
"cwe_ids": [
"CWE-61"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-10T20:32:56Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\nPDM 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.\n\nThis creates an arbitrary file clobber primitive relative to the privileges of the invoking user.\n\n## Affected Behavior\n\n- Project-local config writes can affect files outside the repository\n- The most stable demonstrated sink is `pdm.toml`\n- Related sinks include `.pdm-python` and `.python-version`\n\n## Affected Code\n\n- `src/pdm/project/config.py:303-350`\n- `src/pdm/project/core.py:209-217`\n- `src/pdm/cli/commands/use.py:187-189`\n\n## Technical Details\n\n`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.\n\nThe same general problem exists for other project-local persistence paths that are written directly with no `lstat` / `O_NOFOLLOW` protection.\n\nFor 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.\n\n## Impact\n\n- Arbitrary file clobber as the invoking user\n- Destructive modification of local files outside the repository root\n- Useful primitive for privilege abuse when `pdm` is run in elevated contexts\n\n## Reproduction\n\nPoC:\n\n```bash\n# Replace this with a Python interpreter that can run `python -m pdm`.\nPDM_PY=/path/to/python-with-pdm\ntmpdir=$(mktemp -d)\ntarget=\"$tmpdir/clobbered-target.toml\"\n\ncat \u003e \"$target\" \u003c\u003c\u0027EOF\u0027\n[seed]\nvalue = 1\nEOF\n\nln -s \"$target\" \"$tmpdir/pdm.toml\"\n\ncat \u003e \"$tmpdir/pyproject.toml\" \u003c\u003c\u0027EOF\u0027\n[project]\nname = \"symlink-clobber-demo\"\nversion = \"0.0.1\"\nEOF\n\n(\n cd \"$tmpdir\" \u0026\u0026\n \"$PDM_PY\" -m pdm config -l venv.in_project false\n)\n\ncat \"$target\"\n```\n\nExpected result:\n\n- A temporary project is created\n- `pdm.toml` is a symlink to another TOML file\n- Running `pdm config -l venv.in_project false` modifies the symlink target\n\nObserved output from local validation:\n\n```text\n--- target ---\n[seed]\nvalue = 1\n\n[venv]\nin_project = false\n```\n\n## Severity\n\nMedium\n\n## CVSS v4.0\n\n- Base score: `6.8` (`Medium`)\n- 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`\n\nRationale:\n\n- `AV:L`: exploitation requires local execution of `pdm` against an attacker-prepared checkout\n- `AC:L`: there is no complex constraint once the symlink sink exists\n- `AT:N`: no extra prerequisite beyond the victim running the relevant command is required\n- `PR:N`: the attacker does not need prior privileges on the victim system\n- `UI:A`: the victim must actively run a command that writes project-local state or config\n- `VC:N`: the demonstrated issue is a write primitive, not a direct read primitive\n- `VI:H`: the attacker can cause unauthorized modification of files outside the repository root\n- `VA:L`: file clobber can disrupt local operation, but direct same-step availability impact is lower than a full RCE\n- `SC:N/SI:N/SA:N`: the base score is limited to the directly affected system\n\n## Root Cause\n\nProject-local file sinks are treated as trusted regular files and are written without symlink checks or guarded atomic replacement.\n\n## Recommended Remediation\n\n- Refuse to write project-local config/state files when the destination is a symlink\n- Use `lstat` and `O_NOFOLLOW` where available\n- Avoid resolving attacker-controlled project-local paths before writing\n- Use atomic temp-file replacement only after confirming the destination is a regular file\n\n## Disclosure Notes\n\nThis 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.",
"id": "GHSA-ghq2-5c67-fprm",
"modified": "2026-06-10T20:32:56Z",
"published": "2026-06-10T20:32:56Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pdm-project/pdm/security/advisories/GHSA-ghq2-5c67-fprm"
},
{
"type": "PACKAGE",
"url": "https://github.com/pdm-project/pdm"
},
{
"type": "WEB",
"url": "https://github.com/pdm-project/pdm/releases/tag/2.27.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "PDM: Project-Local State and Config Writes Follow Symlinks"
}
GHSA-GMW6-94GG-2RC2
Vulnerability from github – Published: 2021-08-31 16:03 – Updated: 2022-06-17 20:51Impact
Arbitrary File Creation, Arbitrary File Overwrite, Arbitrary Code Execution
@npmcli/arborist, the library that calculates dependency trees and manages the node_modules folder hierarchy for the npm command line interface, aims to guarantee that package dependency contracts will be met, and the extraction of package contents will always be performed into the expected folder.
This is accomplished by extracting package contents into a project's node_modules folder.
If the node_modules folder of the root project or any of its dependencies is somehow replaced with a symbolic link, it could allow Arborist to write package dependencies to any arbitrary location on the file system.
Note that symbolic links contained within package artifact contents are filtered out, so another means of creating a node_modules symbolic link would have to be employed.
- A
preinstallscript could replacenode_moduleswith a symlink. (This is prevented by using--ignore-scripts.) - An attacker could supply the target with a git repository, instructing them to run
npm install --ignore-scriptsin the root. This may be successful, becausenpm install --ignore-scriptsis typically not capable of making changes outside of the project directory, so it may be deemed safe.
Patches
2.8.2 (included in npm v7.20.7 and above)
Workarounds
Do not run npm install on untrusted codebases, without first ensuring that the node_modules directory in the project is not a symbolic link.
Fix
Prior to extracting any package contents, the node_modules folder into which it is extracted is verified to be a real directory. If it is not, then it is removed.
Caveat: if you are currently relying on creating a symbolic link to the node_modules folder in order to share dependencies between projects, then that will no longer be possible. Please use the npm link command, explicit file:... dependencies, and/or workspaces to share dependencies in a development environment.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@npmcli/arborist"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.8.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2021-39135"
],
"database_specific": {
"cwe_ids": [
"CWE-59",
"CWE-61"
],
"github_reviewed": true,
"github_reviewed_at": "2021-08-31T16:03:00Z",
"nvd_published_at": "2021-08-31T17:15:00Z",
"severity": "HIGH"
},
"details": "### Impact\n\nArbitrary File Creation, Arbitrary File Overwrite, Arbitrary Code Execution\n\n`@npmcli/arborist`, the library that calculates dependency trees and manages the node_modules folder hierarchy for the npm command line interface, aims to guarantee that package dependency contracts will be met, and the extraction of package contents will always be performed into the expected folder.\n\nThis is accomplished by extracting package contents into a project\u0027s `node_modules` folder.\n\nIf the `node_modules` folder of the root project or any of its dependencies is somehow replaced with a symbolic link, it could allow Arborist to write package dependencies to any arbitrary location on the file system.\n\nNote that symbolic links contained within package artifact contents are filtered out, so another means of creating a `node_modules` symbolic link would have to be employed.\n\n1. A `preinstall` script could replace `node_modules` with a symlink. (This is prevented by using `--ignore-scripts`.)\n2. An attacker could supply the target with a git repository, instructing them to run `npm install --ignore-scripts` in the root. This may be successful, because `npm install --ignore-scripts` is typically not capable of making changes outside of the project directory, so it may be deemed safe.\n\n### Patches\n\n2.8.2 (included in npm v7.20.7 and above)\n\n### Workarounds\n\nDo not run `npm install` on untrusted codebases, without first ensuring that the `node_modules` directory in the project is not a symbolic link.\n\n### Fix\n\nPrior to extracting any package contents, the `node_modules` folder into which it is extracted is verified to be a real directory. If it is not, then it is removed.\n\nCaveat: if you are currently relying on creating a symbolic link to the `node_modules` folder in order to share dependencies between projects, then that will no longer be possible. Please use the `npm link` command, explicit `file:...` dependencies, and/or `workspaces` to share dependencies in a development environment.",
"id": "GHSA-gmw6-94gg-2rc2",
"modified": "2022-06-17T20:51:19Z",
"published": "2021-08-31T16:03:34Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/npm/arborist/security/advisories/GHSA-gmw6-94gg-2rc2"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-39135"
},
{
"type": "WEB",
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-389290.pdf"
},
{
"type": "PACKAGE",
"url": "https://github.com/npm/arborist"
},
{
"type": "WEB",
"url": "https://www.npmjs.com/package/@npmcli/arborist"
},
{
"type": "WEB",
"url": "https://www.oracle.com/security-alerts/cpuoct2021.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "UNIX Symbolic Link (Symlink) Following in @npmcli/arborist"
}
Mitigation
Symbolic link attacks often occur when a program creates a tmp directory that stores files/links. Access to the directory should be restricted to the program as to prevent attackers from manipulating the files.
Mitigation MIT-48.1
Strategy: Separation of Privilege
- Follow the principle of least privilege when assigning access rights to entities in a software system.
- Denying access to a file can prevent an attacker from replacing that file with a link to a sensitive file. Ensure good compartmentalization in the system to provide protected areas that can be trusted.
CAPEC-27: Leveraging Race Conditions via Symbolic Links
This attack leverages the use of symbolic links (Symlinks) in order to write to sensitive files. An attacker can create a Symlink link to a target file not otherwise accessible to them. When the privileged program tries to create a temporary file with the same name as the Symlink link, it will actually write to the target file pointed to by the attackers' Symlink link. If the attacker can insert malicious content in the temporary file they will be writing to the sensitive file by using the Symlink. The race occurs because the system checks if the temporary file exists, then creates the file. The attacker would typically create the Symlink during the interval between the check and the creation of the temporary file.