-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 Advisory ID: SYSS-2026-071 Product: GDCM (Grassroots DICOM) Manufacturer: GDCM Project Affected Version(s): 3.3.0 Tested Version(s): 3.3.0 Vulnerability Type: Format String (CWE-134) Risk Level: Medium Solution Status: Open Manufacturer Notification: 2026-07-24 Public Disclosure: 2026-09-23 CVE Reference: Not yet assigned Author of Advisory: Matthias Deeg, SySS GmbH ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Overview: GDCM (Grassroots DICOM) is an open-source C++ library for reading, writing, and processing DICOM (Digital Imaging and Communications in Medicine) medical imaging files (see [1]). The gdcmFilenameGenerator component, used by the gdcmraw command-line tool to generate output filenames for split fragments, is vulnerable to a format string vulnerability. The user-supplied pattern string is used directly as the format string argument to snprintf() without proper validation of the format specifiers. Only the count of % characters is checked (exactly one required), but the specifier that follows is not validated. An attacker can supply format specifiers such as "%n" to write to arbitrary memory addresses, or "%s" to dereference small integers as pointers, causing crashes. Positional parameters like "%5$x" can be used to leak stack data into generated filenames, enabling information disclosure. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Vulnerability Details: The vulnerable code is in the FilenameGenerator::Generate() function at Source/Common/gdcmFilenameGenerator.cxx:94: int res = snprintf( internal, internal_len, Pattern.c_str(), i ); The Pattern string is set by the user via FilenameGenerator::SetPattern(). In the gdcmraw command-line tool, the pattern comes directly from the - -p/--pattern command-line argument: // gdcmraw.cxx:150 pattern = optarg; // user-controlled! // gdcmraw.cxx:353 fg.SetPattern( pattern.c_str() ); The validation in Generate() only counts % characters and requires exactly one but does NOT validate what format specifier follows: const char *pattern = Pattern.c_str(); int num_percent = 0; while( (pattern = strchr( pattern, '%')) ) { ++pattern; ++num_percent; } if ( num_percent != 1 ) { gdcmDebugMacro( "No more than one % in string formatting please" ); return false; } This means patterns like "%s", "%x", "%5$x", and "%n" all pass validation: - "%s" : treats the loop index i as a char* pointer and attempts to dereference it, causing a segmentation fault (information disclosure if the dereferenced memory contains readable data) - "%x" : reads the loop index value as hex and embeds it in the filename - "%5$x": positional parameter that skips past the provided argument to the 5th variadic argument on the stack, leaking arbitrary stack data into the generated filename (information disclosure) - "%n" : interprets the loop index i as an int* and writes the number of bytes written so far to that address, enabling arbitrary memory writes and potential remote code execution The loop index i is of type SizeType (unsigned long / size_t). When interpreted as a pointer, small index values (0, 1, 2, ...) point to invalid memory addresses, causing immediate segmentation faults. The "%n" specifier is particularly dangerous as it enables write-what-where attacks if the attacker can control the stack layout. The exploitability of the vulnerable code with the different shown options depends on on the used compiler settings, for example glibc's FORTIFY_SOURCE. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Proof of Concept (PoC): Using the format specifier "%s" in combination with a multi-fragment DICOM file leads to a segmentation fault as the loop index gets interpreted as char* pointer. When the loop counter is 1, snprintft() attempts to read from address 0x1. gdcmraw -i multifrag.dcm -o output_ --split-frags -p '%s' [1] 13623 segmentation fault (core dumped) gdcmraw -i multifrag.dcm -o output_ --split-frags -p '%s' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Solution: SySS GmbH is not aware of a security update for the described issue. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclosure Timeline: 2026-07-24: Vulnerability reported to manufacturer 2026-07-31: Vulnerability reported to manufacturer again 2026-09-23: Public release of security advisory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ References: [1] GDCM project website https://gdcm.sourceforge.net/ [2] SySS Security Advisory SYSS-2026-071 https://www.syss.de/fileadmin/dokumente/Publikationen/Advisories/SYSS-2026-071.txt [3] SySS GmbH, SySS Responsible Disclosure Policy https://www.syss.de/en/responsible-disclosure-policy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Credits: This security vulnerability was found by Matthias Deeg of SySS GmbH with the assistance of SySS AI. E-Mail: matthias.deeg (at) syss.de Public Key: https://www.syss.de/fileadmin/dokumente/PGPKeys/Matthias_Deeg.asc Key fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclaimer: The information provided in this security advisory is provided "as is" and without warranty of any kind. Details of this security advisory may be updated in order to provide as accurate information as possible. The latest version of this security advisory is available on the SySS website. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Copyright: Creative Commons - Attribution (by) - Version 4.0 URL: https://creativecommons.org/licenses/by/4.0/deed.en -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEE0fCgNfBs5nXNuQUU2aS/ajStTasFAmqzo14ACgkQ2aS/ajSt Tav9/g//YY1BI/NsNANKp/Qcyktk++DxteSlKo2/HFBQmf5k7TgGpp3zBtR5hStl mwhXb5IYZ4YL88ijil6o7ZT+BTd1QKRo77km4H+2mA+e+VpyIncA4QE7LRQBUe/M VI42Po0R0Z43iD7sr4h8e+zRcwI69fCGUDgrO4NtRZqlBdx8toNCxljZU5bPnPKn DK4JVMFD/zU8cdVXuuX3vvQnCUT1YSuJ7xxhQoJtU/V5P3BhhmD4ux4VBRjqh9nJ vz3z1v+Km8CiUA0Shg7aVoBrQ0vXk1pZO5fIUlpS0jr1uhHM9a4lHMyBZLfzJSaf SON1O8c4NmMoRhc0RfTPAqEuXNcZcDH8slncRbIeUeexsgq91lJnERfldplhK1VV 0Z1lMzCMJoZkwoRi3i8tNIKPlS7hre3W9xSekERboJyOdfei4Oj58axf4K5utisW Dtpf3W6eMQ/8kQGmjw0TCFNSW34oPrpzKC0QUwe69/Fymk825jnECmiiT1R2XHqQ lf2+VrxWaEtDrvXumGuaTuis7QDgpJkWAe3BsVazjxp7RPps4SgWQ7wey4SDN6yA mjmFZc1lwcYKFfUgxkGNbUsV3JQY1jIqS3AedwCywgpM+vBxP7iEFHxM5p4V69G0 Mfy0UmOXVBAHJeDLhdhqLzrEaZuBa8EVtIQ0rDrTao9EHEPk5pg= =/tER -----END PGP SIGNATURE-----