All Advisories

Orthanc DICOM Server

Heap Buffer Overflow in DICOM Image Decoder via VR UL Dimensions

Orthanc's DICOM frame-size calculation uses 32-bit arithmetic, and Orthanc does not reject Rows/Columns tags encoded with VR UL (which carries 32-bit values) instead of the standard VR US (16-bit). Crafted dimensions wrap the multiplication to zero; a downstream memcpy then uses the declared width as its pitch, reading far past the actual pixel buffer.

Authored byVolker Schönefeld, Simon WeberDisclosed 2026-04-02Fully disclosed 2026-04-28
SeverityCriticalCVSS 9.8CVSS 3.1 VectorAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HCWECWE-787 (Out-of-bounds Write)ProductOrthanc DICOM ServerAffected VersionsOrthanc <= 1.12.10Fixed In1.12.11CVECVE-2026-5442CERT/CCVU#536588.2

Description

DICOM defines Rows (0028,0010) and Columns (0028,0011) as Value Representation US (Unsigned Short, 2 bytes, max 65535). However, in the Explicit VR Little Endian transfer syntax the VR is encoded inline in the file rather than being looked up from the data dictionary. DCMTK reads the in-file VR and accepts whatever the file declares. Orthanc then accepts these values without checking that they remain within the VR US range.

An attacker encodes Rows and Columns with VR UL (Unsigned Long, 4 bytes), supplying values up to 2^32 - 1. Orthanc's GetFrameSize() then multiplies these in 32-bit arithmetic:

OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp:473-476

// GetHeight() and GetWidth() return unsigned int (32-bit).
// GetHeight() * GetWidth() overflows in 32-bit before promotion to size_t.
// With Rows=65536, Cols=65536: 65536 * 65536 = 2^32 → truncated to 0
return (GetHeight() *
GetWidth() *
GetBytesPerValue() *
GetChannelCount());

View source →

With standard VR US values the multiplication cannot wrap (max 65535*65535 = 4,294,836,225, still below 2^32). The VR UL bypass is essential to drive the wrap.

Downstream, ImageProcessing::Copy() issues a memcpy using the declared width as its pitch. With width=65536 declared but the actual pixel buffer holding only 64 bytes, the copy reads 65536 bytes past the end of the pixel buffer:

OrthancFramework/Sources/Images/ImageProcessing.cpp:576

// memcpy uses declared width as pitch (65536),
// but the pixel data buffer is only 64 bytes
memcpy(target, source, pitch);

View source →

The total crafted DICOM payload is 876 bytes. AddressSanitizer pinpoints the OOB at ImageProcessing.cpp:576, immediately past a 64-byte heap region:

AddressSanitizer trace

==1==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xffff9783ca20
READ of size 65536 at 0xffff9783ca20 thread T18
#0 in __interceptor_memcpy
#1 in memcpy string_fortified.h:29
#2 in Orthanc::ImageProcessing::Copy() ImageProcessing.cpp:576
#3 in Orthanc::ImageProcessing::Convert() ImageProcessing.cpp:689
#4 in Orthanc::DicomImageDecoder::DecodeUncompressedImage() DicomImageDecoder.cpp:607
#5 in Orthanc::DicomImageDecoder::Decode() DicomImageDecoder.cpp:827
#6 in Orthanc::ParsedDicomFile::DecodeFrame() ParsedDicomFile.cpp:1823
#7 in Orthanc::ServerContext::DecodeDicomFrame() ServerContext.cpp:1921
0xffff9783ca20 is located 0 bytes to the right of 64-byte region [0xffff9783c9e0,0xffff9783ca20)
allocated by thread T18 here:
#0 in operator new[]
#1 in DcmElement::newValueField() dcelem.cc:788

On a stock build the memcpy walks past the small heap region and the Orthanc process terminates. The vulnerability is reachable via the same two paths as CVE-2026-5445 (DecodeLookupTable): authenticated HTTP upload + preview, or unauthenticated C-STORE injection on port 4242 under the default DicomAlwaysAllowStore: true. Once stored, every preview request from any user crashes the server — the malicious DICOM is persistent and reproduces the crash on every render.

The VR UL dimension bypass is also the prerequisite for the sister finding CVE-2026-5443, which exploits the same wrap in the PALETTE COLOR validation and decode path. A single dimension-validation fix at parse time addresses both findings.

Impact

  • Persistent denial of service: a single stored 876-byte DICOM crashes the Orthanc process every time any user requests its preview. Restart returns service but the malicious DICOM remains; any subsequent preview crashes the server again.
  • Heap-read primitive: memcpy reads 65536 bytes from a 64-byte buffer, crossing into adjacent heap allocations. Code execution within the Orthanc process's authority has not been demonstrated; the primitive's shape (large, contiguous read of attacker-controlled length) makes it a plausible target for further exploitation research.
  • Reachable unauthenticated for the planting step under Orthanc's default configuration (DicomAlwaysAllowStore: true); the trigger requires only a preview request from any read-level user.

Mitigation

Update Orthanc to version 1.12.11 or later. The fix performs both dimension validation at parse time (rejecting Rows/Columns values above 65535, the VR US ceiling) and 64-bit arithmetic with explicit overflow checks in GetFrameSize(). As immediate defense in depth, set DicomAlwaysAllowStore: false in orthanc.json and configure an AET allow-list, which closes the unauthenticated planting vector.

Defender's Checklist

  • Verify your version.

    curl -u <user>:<pass> http://<orthanc>:8042/system | jq .Version — the patched range begins at 1.12.11.

  • Close the unauthenticated C-STORE planting vector.

    Set DicomAlwaysAllowStore: false in orthanc.json and define an explicit DicomModalities allow-list of legitimate AETs. Otherwise any host that can reach port 4242 can plant the persistent crashing DICOM unauthenticated.

  • Quarantine and review the DICOM store before patching.

    Search the store for studies whose Rows or Columns exceed 65535 — only possible with VR UL encoding and by construction malicious, since DICOM defines these tags as VR US (max 65535). Quarantine before patching, since the next preview request crashes the server.

  • Audit who has preview access.

    Once a malicious study is stored, any read-level user requesting GET /instances/*/preview crashes the process. Limit preview access at your reverse proxy to the IPs of integration points and viewers that need it.

  • Watch for crash-restart cycles tied to preview requests.

    Alert on Orthanc restarts (journalctl -u orthanc | grep -E 'SIGSEGV|killed') that closely follow GET /instances/*/preview log entries. Repeated crashes from the same study ID indicate a stored attack.

  • Confirm crash recovery is configured.

    Until the store is purged of the malicious study, every preview crashes the process. Tight supervisor restart (systemd, Kubernetes liveness probes, Docker --restart) keeps service available between requests but does not mitigate the bug.

Severity Reasoning

AV:NReachable over the network via Orthanc's HTTP REST API and via DICOM C-STORE on port 4242.AC:LA single 876-byte crafted DICOM with VR UL-encoded dimensions. No timing or environmental conditions.PR:NThe published vector reflects deployments where preview rendering is exposed without HTTP authentication and the C-STORE listener accepts unauthenticated requests under default DicomAlwaysAllowStore: true.UI:NNo interaction by a second user is needed; planting and triggering can both be performed by the same actor.S:UOnly the Orthanc process is affected; no out-of-process resources are reached through this primitive.C:HPlausible RCE within the Orthanc process's authority would expose process memory and any data it can read. Not demonstrated.I:HSame primitive within the same authority would allow modifying in-memory state and any data the process can write. Not demonstrated.A:HPersistent crash: the stored DICOM crashes the process on every preview request from any user.

References

How We Can Help

Who We Are

The security researchers behind this advisory.

Dr. Simon Weber Profile

Dr. rer. nat. Simon Weber

Senior Pentester & MedSec Researcher

I evaluate your SaMD with the same industry-defining security insight I contributed to the BAK MV for the revision of the B3S standard.

  • PhD on Hospital Cybersecurity
  • Critical vulnerabilities found in hospital systems
  • Alumni of THB MedSec Research Group
  • gematik Security Hero
Volker Schönefeld Profile

Dipl.-Inf. Volker Schönefeld

Senior Application Security Expert

As a former CTO and developer turned pentester, I work alongside your team to uncover vulnerabilities and find solutions that fit your architecture.

  • 20+ years as CTO, 50M+ app downloads
  • Architected and secured large-scale IoT fleets
  • Certified Web Exploitation Specialist
  • gematik Security Hero

Looking for a Penetration Test?

Machine Spirits specializes in security assessments for medical devices and healthcare IT. From MDR penetration testing to C5 cloud compliance, we help MedTech companies meet regulatory requirements.