{"url":"http://public2.vulnerablecode.io/api/packages/989648?format=json","purl":"pkg:pypi/pydicom@1.4.2","type":"pypi","namespace":"","name":"pydicom","version":"1.4.2","qualifiers":{},"subpath":"","is_vulnerable":true,"next_non_vulnerable_version":"2.4.5","latest_non_vulnerable_version":"3.0.2","affected_by_vulnerabilities":[{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/91417?format=json","vulnerability_id":"VCID-7ww6-288v-sbfw","summary":"pydicom has a path traversal in FileSet/DICOMDIR ReferencedFileID allows file access outside the File-set root\n### Summary\nA crafted `DICOMDIR` can set `ReferencedFileID` to a path outside the File-set root. `pydicom` resolves the path only to confirm that it exists, but does not verify that the resolved path remains under the File-set root. Subsequent public `FileSet` operations such as `copy()`, `write()`, and `remove()+write(use_existing=True)` use that unchecked path in file I/O operations. This allows arbitrary file read/copy and, in some flows, move/delete outside the File-set root.\n\n### Details\nVerified on `pydicom 3.1.0.dev0`.\n\nRelevant logic is in `src/pydicom/fileset.py`:\n\n- `RecordNode._file_id` converts `ReferencedFileID` directly to `Path(...)`\n- `FileSet.load()` checks only `(root / file_id).resolve(strict=True)` to confirm existence\n- `FileSet.load()` does not verify that the final resolved path is contained within the File-set root\n- `FileInstance.path` returns `self.file_set.path / self.node._file_id`\n- `FileSet.copy()` uses `shutil.copyfile(instance.path, dst)`\n- `FileSet.write()` uses `Path(instance.path).unlink()` and `shutil.move(...)`\n\nBecause there is no containment check such as `resolved.relative_to(root.resolve(strict=True))`, a malicious `DICOMDIR` can reference:\n\n- absolute paths such as `/etc/passwd`\n- traversal paths such as `../...`\n- syntactically conformant file IDs that escape via symlinks\n\nThis is not limited to obviously invalid VR input. Even when `pydicom` emits warnings for invalid `ReferencedFileID` values, the operation is not blocked. I also confirmed a symlink-based variant using a conformant file ID.\n\nA realistic server-side scenario is:\n\n1. a user uploads a DICOM File-set zip\n2. the server loads the uploaded `DICOMDIR` using `FileSet`\n3. the server re-exports or reorganizes the File-set using `FileSet.copy()` or `FileSet.write()`\n4. a server-local file referenced by the malicious `DICOMDIR` is included in the exported result\n\n### PoC\nMinimal reproduction:\n\n1. Copy a sample File-set that contains a valid `DICOMDIR`\n2. Modify one `DirectoryRecordSequence` item so that `ReferencedFileID = \"/etc/passwd\"` (or `/tmp/secret.txt`)\n3. Load it with `FileSet(ds)` or `FileSet(path_to_dicomdir)`\n4. Call `FileSet.copy(new_root)`\n5. Observe that the exported File-set contains the contents of the referenced external file\n\nExample:\n\n```python\nfrom pathlib import Path\nfrom tempfile import mkdtemp\nimport shutil\nfrom pydicom import dcmread\nfrom pydicom.fileset import FileSet\n\nbase = Path(\"src/pydicom/data/test_files/dicomdirtests\")\nroot = Path(mkdtemp(prefix=\"fsroot_\"))\nout = Path(mkdtemp(prefix=\"fsout_\"))\n\nshutil.copy2(base / \"DICOMDIR\", root / \"DICOMDIR\")\nfor d in (\"77654033\", \"98892003\", \"98892001\"):\n    shutil.copytree(base / d, root / d)\n\nds = dcmread(root / \"DICOMDIR\")\nitem = next(x for x in ds.DirectoryRecordSequence if \"ReferencedFileID\" in x)\nitem.ReferencedFileID = \"/etc/passwd\"\n\nfs = FileSet(ds)\nfs.copy(out)\n```\n\nI also verified the issue in a simple web import/export demo where an uploaded malicious File-set caused /etc/passwd to be copied into the exported result.\n\nIf useful, I can provide the exact malicious sample and the demo environment separately.\n\n### Impact\nThis is a path traversal / root containment bypass in FileSet handling.\n\nObserved impact:\n\narbitrary file read/copy outside the File-set root via FileSet.copy()\narbitrary file move outside the File-set root via FileSet.write()\narbitrary file delete outside the File-set root via FileSet.remove(...); write(use_existing=True)\nAffected applications are those that accept untrusted DICOMDIR / File-set input and then call public FileSet workflows such as load(), copy(), write(), or remove().\n\nA realistic impact is server-side file disclosure in import/export workflows.","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-32711","reference_id":"","reference_type":"","scores":[{"value":"8e-05","scoring_system":"epss","scoring_elements":"0.00848","published_at":"2026-06-09T12:55:00Z"},{"value":"8e-05","scoring_system":"epss","scoring_elements":"0.0085","published_at":"2026-06-07T12:55:00Z"},{"value":"8e-05","scoring_system":"epss","scoring_elements":"0.00852","published_at":"2026-06-06T12:55:00Z"},{"value":"8e-05","scoring_system":"epss","scoring_elements":"0.00851","published_at":"2026-06-05T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-32711"},{"reference_url":"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-32711","reference_id":"","reference_type":"","scores":[],"url":"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-32711"},{"reference_url":"https://github.com/pydicom/pydicom","reference_id":"","reference_type":"","scores":[{"value":"7.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/pydicom/pydicom"},{"reference_url":"https://github.com/pydicom/pydicom/commit/6414f01a053dff925578799f5a7208d2ae585e82","reference_id":"","reference_type":"","scores":[{"value":"7.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-03-20T16:41:24Z/"}],"url":"https://github.com/pydicom/pydicom/commit/6414f01a053dff925578799f5a7208d2ae585e82"},{"reference_url":"https://github.com/pydicom/pydicom/releases/tag/v3.0.2","reference_id":"","reference_type":"","scores":[{"value":"7.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-03-20T16:41:24Z/"}],"url":"https://github.com/pydicom/pydicom/releases/tag/v3.0.2"},{"reference_url":"https://github.com/pydicom/pydicom/security/advisories/GHSA-v856-2rf8-9f28","reference_id":"","reference_type":"","scores":[{"value":"7.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-03-20T16:41:24Z/"}],"url":"https://github.com/pydicom/pydicom/security/advisories/GHSA-v856-2rf8-9f28"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-32711","reference_id":"","reference_type":"","scores":[{"value":"7.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-32711"},{"reference_url":"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1131492","reference_id":"1131492","reference_type":"","scores":[],"url":"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1131492"},{"reference_url":"https://github.com/advisories/GHSA-v856-2rf8-9f28","reference_id":"GHSA-v856-2rf8-9f28","reference_type":"","scores":[{"value":"HIGH","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-v856-2rf8-9f28"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/113579?format=json","purl":"pkg:pypi/pydicom@2.4.5","is_vulnerable":false,"affected_by_vulnerabilities":[],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:pypi/pydicom@2.4.5"},{"url":"http://public2.vulnerablecode.io/api/packages/989665?format=json","purl":"pkg:pypi/pydicom@3.0.0rc1","is_vulnerable":false,"affected_by_vulnerabilities":[],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:pypi/pydicom@3.0.0rc1"},{"url":"http://public2.vulnerablecode.io/api/packages/113578?format=json","purl":"pkg:pypi/pydicom@3.0.2","is_vulnerable":false,"affected_by_vulnerabilities":[],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:pypi/pydicom@3.0.2"}],"aliases":["CVE-2026-32711","GHSA-v856-2rf8-9f28"],"risk_score":4.0,"exploitability":"0.5","weighted_severity":"8.0","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-7ww6-288v-sbfw"}],"fixing_vulnerabilities":[],"risk_score":"4.0","resource_url":"http://public2.vulnerablecode.io/packages/pkg:pypi/pydicom@1.4.2"}