Invalid C++ downcast parsing the DICOM meta-header group length in DCMTK
fixed
Details
DCMTK OFFIS / Open Connections through 4ac1337; fixed in 2c8b4288d CWE-843 low fixed Timeline
11 Aug 2026 19 Aug 2026 19 Aug 2026 24 Aug 2026 References
Notes
Loading a crafted DICOM file whose File Meta Information Group Length element
(0002,0000) is encoded with a value representation other than UL causes
DcmMetaInfo::readGroupLength() (dcmdata/libsrc/dcmetinf.cc) to static_cast
that element to DcmUnsignedLong * after checking only its tag, never its
type. The element the parser actually constructed is a different DcmElement
subclass, so the cast is an invalid downcast — undefined behaviour, flagged by
UBSan’s vptr check as “downcast of address … which does not point to an object
of type ‘DcmUnsignedLong’”. It is reachable from DcmFileFormat::loadFile() on
any untrusted .dcm.
Severity is low: getUint32() is virtual, so the call dispatches to the real
object’s implementation (which returns an error for a non-numeric element) rather
than misinterpreting memory. There is no demonstrated memory-corruption or
information-leak consequence — but it is a genuine type-safety defect on
attacker-controlled input, and a reasonable hardening fix. A 20-byte PoC
reproduces it under a -fsanitize=vptr build.
The bug was found with an AFL++ / ASan+UBSan campaign over the DICOM file parser.
DCMTK’s canonical repository is git.dcmtk.org and it routes bug reports through
its Redmine tracker rather than GitHub pull requests, so the report went to the
project’s bug address. Michael Onken accepted it and fixed it in master commit
2c8b4288d (“Fixed invalid downcast for non-UL group length VR.”), which adds an
ident() == EVR_UL guard before the cast — the one-line fix I proposed — and
credits glitchfox (Benjamin Ali), closing Redmine #1276.
I rebuilt dcmdata at both the fix commit and its parent under
-fsanitize=address,undefined with the vptr check enabled and replayed the PoC.
At the parent it trips the invalid-downcast diagnostic at dcmetinf.cc:382; at the
fix commit the file is rejected cleanly as corrupted meta information with no
sanitizer finding.