[med-svn] [Git][med-team/dcmtk][master] 3 commits: CVE-2026-5663.patch: new: fix CVE-2026-5663.

Étienne Mollier (@emollier) gitlab at salsa.debian.org
Wed Jun 3 20:14:02 BST 2026



Étienne Mollier pushed to branch master at Debian Med / dcmtk


Commits:
449d8d60 by Étienne Mollier at 2026-06-03T19:21:14+02:00
CVE-2026-5663.patch: new: fix CVE-2026-5663.

This change introduces guardrails to prevent risks of shell code
injection.

Closes: #1133001

- - - - -
5d6c0649 by Étienne Mollier at 2026-06-03T19:24:07+02:00
CVE-2026-10528-partial.patch: new: fix needed by orthanc.

This patch introduce the part of the mitigation against CVE-2026-10528
affecting orthanc that needs to be applied on the side of dcmtk.  See
also Debian bug #1138713.

- - - - -
90494a58 by Étienne Mollier at 2026-06-03T21:13:24+02:00
d/changelog: update the changelog.

- - - - -


4 changed files:

- debian/changelog
- + debian/patches/CVE-2026-10528-partial.patch
- + debian/patches/CVE-2026-5663.patch
- debian/patches/series


Changes:

=====================================
debian/changelog
=====================================
@@ -3,7 +3,16 @@ dcmtk (3.7.0+really3.7.0-3) UNRELEASED; urgency=medium
   [ Pino Toscano ]
   * d/patches/hurd.patch: new, fix the build on GNU/Hurd.
 
- -- Étienne Mollier <emollier at debian.org>  Wed, 27 May 2026 20:18:20 +0200
+  [ Étienne Mollier ]
+  * CVE-2026-5663.patch: new: fix CVE-2026-5663.
+    This change introduces guardrails to prevent risks of shell code
+    injection. (Closes: #1133001)
+  * CVE-2026-10528-partial.patch: new: fix needed by orthanc.
+    This patch introduce the part of the mitigation against CVE-2026-10528
+    affecting orthanc that needs to be applied on the side of dcmtk.  See
+    also Debian bug #1138713.
+
+ -- Étienne Mollier <emollier at debian.org>  Wed, 03 Jun 2026 19:27:46 +0200
 
 dcmtk (3.7.0+really3.7.0-2) unstable; urgency=medium
 


=====================================
debian/patches/CVE-2026-10528-partial.patch
=====================================
@@ -0,0 +1,1358 @@
+Description: Add sequence nesting depth limit for parsing
+ Track sequence nesting depth on DcmInputStream during parsing. When the
+ depth exceeds a configurable limit, parsing is aborted with
+ EC_NestingDepthLimitExceeded. This prevents stack overflow from
+ excessively nested DICOM sequences.
+ .
+ The default limit is controlled by the compile-time macro
+ DCMTK_MAX_SEQUENCE_NESTING (default: 64). It can be overridden per parse
+ operation via the runtime API:
+ .
+ - DcmInputStream::setMaxNestingDepth() for direct stream access
+ - DcmItem::setMaxNestingDepth() (inherited by DcmDataset) for loadFile()
+   and read()
+ - DcmFileFormat::setMaxNestingDepth() for loadFile() and read(),
+   forwarded to the contained dataset
+ - DcmSCP::setMaxNestingDepth() and DcmSCU::setMaxNestingDepth() for
+   datasets received over the network via receiveDIMSEDataset()
+ .
+ The runtime setter uses Sint32 semantics:
+   0 = compile-time default, -1 = unlimited, >0 = limit
+ .
+ Note: the specific EC_NestingDepthLimitExceeded error code is not yet
+ surfaced through the DIMSE layer; DIMSE_receiveDataSetInMemory() maps
+ all parse errors to DIMSE_RECEIVEFAILED.
+ .
+ Thanks to the IN-CYPHER OSS Security Team for the report, detailed
+ analysis and proof of concept.
+ .
+ This closes DCMTK Bug #1191.
+Author: Michael Onken <onken at open-connections.de>
+Applied-Upstream: 885ff0f10372bd589b5f44cea974f28a3964cb0f
+Last-Update: 2026-04-11
+Bug: https://support.dcmtk.org/redmine/issues/1191
+Bug-Debian: https://bugs.debian.org/1138713
+Reviewed-By: Étienne Mollier <emollier at debian.org>
+
+--- dcmtk.orig/config/docs/macros.txt
++++ dcmtk/config/docs/macros.txt
+@@ -109,6 +109,21 @@
+     dcmtk::log4cplus::threadCleanup() should be called by the user code in
+     order to clean-up oflog's thread local storage.
+ 
++DCMTK_MAX_SEQUENCE_NESTING
++  Affected: dcmdata
++  Type of modification: Compile-time tunable
++  Explanation: Defines the default maximum permitted sequence nesting depth
++    during DICOM parsing.  Deeply nested sequences can cause a stack overflow
++    by exhausting the call stack through unbounded recursion.  When this macro
++    is not defined, the default limit of 64 nested sequence levels is used.
++    Real-world DICOM data rarely exceeds 5-10 nesting levels.  The limit can
++    be changed at runtime per parse operation via
++    DcmInputStream::setMaxNestingDepth(), DcmItem::setMaxNestingDepth(), or
++    DcmFileFormat::setMaxNestingDepth().  Setting the runtime value to -1
++    disables the check entirely.
++    Minimum value: 1.  Values less than 1 cause a compile-time error.
++    Maximum value: 2147483647 (aligned to 32-bit signed integer runtime API).
++
+ DCMTK_MERGE_STDERR_TO_STDOUT
+   Affected: dcmdata
+   Type of modification: Activates feature
+--- dcmtk.orig/dcmdata/include/dcmtk/dcmdata/dcerror.h
++++ dcmtk/dcmdata/include/dcmtk/dcmdata/dcerror.h
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2025, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -200,6 +200,8 @@
+ extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_UnsupportedURIType;
+ /// Execution of command line failed
+ extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_CommandLineFailed;
++/// Maximum sequence nesting depth exceeded (stack overflow protection)
++extern DCMTK_DCMDATA_EXPORT const OFConditionConst EC_NestingDepthLimitExceeded;
+ 
+ ///@}
+ 
+--- dcmtk.orig/dcmdata/include/dcmtk/dcmdata/dcfilefo.h
++++ dcmtk/dcmdata/include/dcmtk/dcmdata/dcfilefo.h
+@@ -514,6 +514,35 @@
+ 
+     /// implementation version name to write in the meta-header
+     OFString ImplementationVersionName;
++
++    /// maximum sequence nesting depth for parsing
++    /// (0 = compile-time default DCMTK_MAX_SEQUENCE_NESTING, -1 = unlimited)
++    Sint32 MaxNestingDepth;
++
++  public:
++
++    /** set the maximum permitted sequence nesting depth for parsing.
++     *  Applied to the input stream in loadFile() and read(), and also
++     *  forwarded to the contained dataset.
++     *  - Value 0 (default): apply the compile-time default
++     *    (DCMTK_MAX_SEQUENCE_NESTING, default is 64)
++     *  - Value -1: disable the check (allow unlimited nesting)
++     *  - Value > 0: use this value as the maximum permitted nesting depth
++     *  @param maxDepth maximum nesting depth setting
++     */
++    void setMaxNestingDepth(Sint32 maxDepth)
++    {
++        MaxNestingDepth = maxDepth;
++        DcmDataset* dset = getDataset();
++        if (dset)
++            dset->setMaxNestingDepth(maxDepth);
++    }
++
++    /** return the maximum permitted sequence nesting depth for parsing.
++     *  @return maximum nesting depth setting
++     *    (0 = compile-time default DCMTK_MAX_SEQUENCE_NESTING, -1 = unlimited)
++     */
++    Sint32 getMaxNestingDepth() const { return MaxNestingDepth; }
+ };
+ 
+ 
+--- dcmtk.orig/dcmdata/include/dcmtk/dcmdata/dcistrma.h
++++ dcmtk/dcmdata/include/dcmtk/dcmdata/dcistrma.h
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2018, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -224,6 +224,40 @@
+    */
+   virtual DcmInputStreamFactory *newFactory() const = 0;
+ 
++  /** returns the current sequence nesting depth.
++   *  This counter is used to prevent stack overflow from deeply nested
++   *  DICOM sequences in malicious input files.
++   *  @return current nesting depth
++   */
++  Uint32 nestingDepth() const;
++
++  /** increments the sequence nesting depth counter.
++   *  @return the new nesting depth after incrementing
++   */
++  Uint32 incrementNestingDepth();
++
++  /** decrements the sequence nesting depth counter.
++   *  Does nothing if the counter is already zero.
++   */
++  void decrementNestingDepth();
++
++  /** returns the maximum permitted sequence nesting depth for this stream.
++   *  A value of 0 means the compile-time default (DCMTK_MAX_SEQUENCE_NESTING) applies.
++   *  A value of -1 means the check is disabled (unlimited nesting).
++   *  @return maximum nesting depth setting
++   */
++  Sint32 maxNestingDepth() const;
++
++  /** sets the maximum permitted sequence nesting depth for this stream.
++   *  Must be called before parsing begins.
++   *  - Value 0 (default): apply the compile-time default
++   *    (DCMTK_MAX_SEQUENCE_NESTING, default is 64)
++   *  - Value -1: disable the check (allow unlimited nesting)
++   *  - Value > 0: use this value as the maximum permitted nesting depth
++   *  @param maxDepth maximum nesting depth setting
++   */
++  void setMaxNestingDepth(Sint32 maxDepth);
++
+   /** marks the current stream position for a later putback operation,
+    *  overwriting a possibly existing prior putback mark.
+    *  The DcmObject read methods rely on the possibility to putback
+@@ -272,6 +306,12 @@
+ 
+   /// putback marker
+   offile_off_t mark_;
++
++  /// current sequence nesting depth (for stack overflow protection)
++  Uint32 nestingDepth_;
++
++  /// maximum permitted sequence nesting depth (0 = default 64, -1 = unlimited)
++  Sint32 maxNestingDepth_;
+ };
+ 
+ 
+--- dcmtk.orig/dcmdata/include/dcmtk/dcmdata/dcitem.h
++++ dcmtk/dcmdata/include/dcmtk/dcmdata/dcitem.h
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2025, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -1573,6 +1573,29 @@
+ 
+     /// cache for private creator tags and identifiers
+     DcmPrivateTagCache privateCreatorCache;
++
++    /// maximum sequence nesting depth for parsing
++    /// (0 = compile-time default DCMTK_MAX_SEQUENCE_NESTING, -1 = unlimited)
++    Sint32 maxNestingDepth;
++
++  public:
++
++    /** set the maximum permitted sequence nesting depth for parsing.
++     *  This limit is applied to the input stream before parsing in
++     *  loadFile() and read().
++     *  - Value 0 (default): apply the compile-time default
++     *    (DCMTK_MAX_SEQUENCE_NESTING, default is 64)
++     *  - Value -1: disable the check (allow unlimited nesting)
++     *  - Value > 0: use this value as the maximum permitted nesting depth
++     *  @param maxDepth maximum nesting depth setting
++     */
++    void setMaxNestingDepth(Sint32 maxDepth) { maxNestingDepth = maxDepth; }
++
++    /** return the maximum permitted sequence nesting depth for parsing.
++     *  @return maximum nesting depth setting
++     *    (0 = compile-time default DCMTK_MAX_SEQUENCE_NESTING, -1 = unlimited)
++     */
++    Sint32 getMaxNestingDepth() const { return maxNestingDepth; }
+ };
+ 
+ /** Checks whether left hand side item is smaller than right hand side
+--- dcmtk.orig/dcmdata/include/dcmtk/dcmdata/dcobject.h
++++ dcmtk/dcmdata/include/dcmtk/dcmdata/dcobject.h
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2024, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -50,6 +50,18 @@
+ 
+ // Undefined Length Identifier now defined in dctypes.h
+ 
++// Default maximum sequence nesting depth (can be overridden at compile time).
++// Must be in the range [1, 2147483647].
++#ifndef DCMTK_MAX_SEQUENCE_NESTING
++#define DCMTK_MAX_SEQUENCE_NESTING 64
++#endif
++#if DCMTK_MAX_SEQUENCE_NESTING < 1
++#error "DCMTK_MAX_SEQUENCE_NESTING must be >= 1"
++#endif
++#if DCMTK_MAX_SEQUENCE_NESTING > 2147483647
++#error "DCMTK_MAX_SEQUENCE_NESTING must be <= 2147483647"
++#endif
++
+ // Maximum number of read bytes for a Value Element
+ const Uint32 DCM_MaxReadLength = 4096;
+ 
+--- dcmtk.orig/dcmdata/libsrc/dcdatset.cc
++++ dcmtk/dcmdata/libsrc/dcdatset.cc
+@@ -647,6 +647,9 @@
+         {
+             /* use stdin stream */
+             DcmStdinStream inStream;
++            /* apply configured nesting depth limit */
++            if (getMaxNestingDepth() > 0)
++                inStream.setMaxNestingDepth(getMaxNestingDepth());
+ 
+             /* clear this object */
+             l_error = clear();
+@@ -670,6 +673,9 @@
+         } else {
+             /* open file for input */
+             DcmInputFileStream fileStream(fileName);
++            /* apply configured nesting depth limit */
++            if (getMaxNestingDepth() > 0)
++                fileStream.setMaxNestingDepth(getMaxNestingDepth());
+ 
+             /* check stream status */
+             l_error = fileStream.status();
+--- dcmtk.orig/dcmdata/libsrc/dcerror.cc
++++ dcmtk/dcmdata/libsrc/dcerror.cc
+@@ -91,6 +91,7 @@
+ makeOFConditionConst(EC_BulkDataURINotSupported,         OFM_dcmdata, 66, OF_error, "BulkDataURI not yet supported"              );
+ makeOFConditionConst(EC_UnsupportedURIType,              OFM_dcmdata, 67, OF_error, "Unsupported URI type"                       );
+ makeOFConditionConst(EC_CommandLineFailed,               OFM_dcmdata, 68, OF_error, "Execution of command line failed"           );
++makeOFConditionConst(EC_NestingDepthLimitExceeded,       OFM_dcmdata, 69, OF_error, "Maximum sequence nesting depth exceeded"    );
+ 
+ const unsigned short EC_CODE_CannotSelectCharacterSet     = 35;
+ const unsigned short EC_CODE_CannotConvertCharacterSet    = 36;
+--- dcmtk.orig/dcmdata/libsrc/dcfilefo.cc
++++ dcmtk/dcmdata/libsrc/dcfilefo.cc
+@@ -54,7 +54,8 @@
+   : DcmSequenceOfItems(DCM_InternalUseTag),
+     FileReadMode(ERM_autoDetect),
+     ImplementationClassUID(OFFIS_IMPLEMENTATION_CLASS_UID),
+-    ImplementationVersionName(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME)
++    ImplementationVersionName(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME),
++    MaxNestingDepth(0)
+ {
+     DcmMetaInfo *MetaInfo = new DcmMetaInfo();
+     DcmSequenceOfItems::itemList->insert(MetaInfo);
+@@ -71,7 +72,8 @@
+   : DcmSequenceOfItems(DCM_InternalUseTag),
+     FileReadMode(ERM_autoDetect),
+     ImplementationClassUID(OFFIS_IMPLEMENTATION_CLASS_UID),
+-    ImplementationVersionName(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME)
++    ImplementationVersionName(OFFIS_DTK_IMPLEMENTATION_VERSION_NAME),
++    MaxNestingDepth(0)
+ {
+     DcmMetaInfo *MetaInfo = new DcmMetaInfo();
+     DcmSequenceOfItems::itemList->insert(MetaInfo);
+@@ -99,7 +101,8 @@
+   : DcmSequenceOfItems(old),
+     FileReadMode(old.FileReadMode),
+     ImplementationClassUID(old.ImplementationClassUID),
+-    ImplementationVersionName(old.ImplementationVersionName)
++    ImplementationVersionName(old.ImplementationVersionName),
++    MaxNestingDepth(old.MaxNestingDepth)
+ {
+ }
+ 
+@@ -128,6 +131,7 @@
+     FileReadMode = obj.FileReadMode;
+     ImplementationClassUID = obj.ImplementationClassUID;
+     ImplementationVersionName = obj.ImplementationVersionName;
++    MaxNestingDepth = obj.MaxNestingDepth;
+   }
+ 
+   return *this;
+@@ -942,6 +946,9 @@
+         {
+             /* use stdin stream */
+             DcmStdinStream inStream;
++            /* apply configured nesting depth limit */
++            if (MaxNestingDepth != 0)
++                inStream.setMaxNestingDepth(MaxNestingDepth);
+ 
+             /* clear this object */
+             l_error = clear();
+@@ -972,6 +979,9 @@
+         } else {
+             /* open file for output */
+             DcmInputFileStream fileStream(fileName);
++            /* apply configured nesting depth limit */
++            if (MaxNestingDepth > 0)
++                fileStream.setMaxNestingDepth(MaxNestingDepth);
+ 
+             /* check stream status */
+             l_error = fileStream.status();
+--- dcmtk.orig/dcmdata/libsrc/dcistrma.cc
++++ dcmtk/dcmdata/libsrc/dcistrma.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2010, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -29,6 +29,8 @@
+ , compressionFilter_(NULL)
+ , tell_(0)
+ , mark_(0)
++, nestingDepth_(0)
++, maxNestingDepth_(0)
+ {
+ }
+ 
+@@ -94,6 +96,32 @@
+   return current_;
+ }
+ 
++Uint32 DcmInputStream::nestingDepth() const
++{
++  return nestingDepth_;
++}
++
++Uint32 DcmInputStream::incrementNestingDepth()
++{
++  return ++nestingDepth_;
++}
++
++void DcmInputStream::decrementNestingDepth()
++{
++  if (nestingDepth_ > 0)
++    --nestingDepth_;
++}
++
++Sint32 DcmInputStream::maxNestingDepth() const
++{
++  return maxNestingDepth_;
++}
++
++void DcmInputStream::setMaxNestingDepth(Sint32 maxDepth)
++{
++  maxNestingDepth_ = maxDepth;
++}
++
+ OFCondition DcmInputStream::installCompressionFilter(E_StreamCompression filterType)
+ {
+   OFCondition result = EC_Normal;
+--- dcmtk.orig/dcmdata/libsrc/dcitem.cc
++++ dcmtk/dcmdata/libsrc/dcitem.cc
+@@ -83,7 +83,8 @@
+     elementList(NULL),
+     lastElementComplete(OFTrue),
+     fStartPosition(0),
+-    privateCreatorCache()
++    privateCreatorCache(),
++    maxNestingDepth(0)
+ {
+     elementList = new DcmList;
+ }
+@@ -95,7 +96,8 @@
+     elementList(NULL),
+     lastElementComplete(OFTrue),
+     fStartPosition(0),
+-    privateCreatorCache()
++    privateCreatorCache(),
++    maxNestingDepth(0)
+ {
+     elementList = new DcmList;
+ }
+@@ -106,7 +108,8 @@
+     elementList(new DcmList),
+     lastElementComplete(old.lastElementComplete),
+     fStartPosition(old.fStartPosition),
+-    privateCreatorCache()
++    privateCreatorCache(),
++    maxNestingDepth(old.maxNestingDepth)
+ {
+     if (!old.elementList->empty())
+     {
+@@ -136,6 +139,7 @@
+         // copy DcmItem's member variables
+         lastElementComplete = obj.lastElementComplete;
+         fStartPosition = obj.fStartPosition;
++        maxNestingDepth = obj.maxNestingDepth;
+         if (!obj.elementList->empty())
+         {
+             elementList->seek(ELP_first);
+@@ -1394,6 +1398,10 @@
+         return errorFlag;
+     }
+ 
++    /* apply configured nesting depth limit to the input stream (0 = use default, skip override) */
++    if (getMaxNestingDepth() != 0)
++        inStream.setMaxNestingDepth(getMaxNestingDepth());
++
+     /* figure out if the stream reported an error */
+     errorFlag = inStream.status();
+     /* if the stream reported an error or if it is the end of the */
+--- dcmtk.orig/dcmdata/libsrc/dcsequen.cc
++++ dcmtk/dcmdata/libsrc/dcsequen.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2023, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -704,6 +704,23 @@
+         errorFlag = EC_IllegalCall;
+     else
+     {
++        const Uint32 depth = inStream.incrementNestingDepth();
++        const Sint32 maxDepthSetting = inStream.maxNestingDepth();
++        /* -1 = unlimited; 0 = use built-in default (DCMTK_MAX_SEQUENCE_NESTING); > 0 = custom limit */
++        const Uint32 effectiveMax = (maxDepthSetting == 0) ? DCMTK_MAX_SEQUENCE_NESTING
++                                  : (maxDepthSetting < 0)  ? 0   /* unlimited */
++                                  : OFstatic_cast(Uint32, maxDepthSetting);
++        if (effectiveMax > 0 && depth > effectiveMax)
++        {
++            DCMDATA_ERROR("DcmSequenceOfItems: Maximum nesting depth (" << effectiveMax
++                << ") exceeded while parsing sequence " << getTagName() << " " << getTag());
++            inStream.decrementNestingDepth();
++            errorFlag = EC_NestingDepthLimitExceeded;
++            // dump information if required
++            DCMDATA_TRACE("DcmSequenceOfItems::read() returns error = " << errorFlag.text());
++            return errorFlag;
++        }
++
+         errorFlag = inStream.status();
+ 
+         if (errorFlag.good() && inStream.eos())
+@@ -773,6 +790,7 @@
+             errorFlag = EC_Normal;
+         if (errorFlag.good())
+             setTransferState(ERW_ready);      // sequence is complete
++        inStream.decrementNestingDepth();
+     }
+     // dump information if required
+     DCMDATA_TRACE("DcmSequenceOfItems::read() returns error = " << errorFlag.text());
+--- dcmtk.orig/dcmdata/tests/CMakeLists.txt
++++ dcmtk/dcmdata/tests/CMakeLists.txt
+@@ -11,6 +11,7 @@
+   ti2dbmp.cc
+   titem.cc
+   tmatch.cc
++  tnesting.cc
+   tnewdcme.cc
+   tparent.cc
+   tparser.cc
+--- dcmtk.orig/dcmdata/tests/Makefile.dep
++++ dcmtk/dcmdata/tests/Makefile.dep
+@@ -712,6 +712,73 @@
+  ../include/dcmtk/dcmdata/dcvr.h \
+  ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+  ../include/dcmtk/dcmdata/dcmatch.h
++tnesting.o: tnesting.cc ../../config/include/dcmtk/config/osconfig.h \
++ ../../ofstd/include/dcmtk/ofstd/oftest.h \
++ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
++ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
++ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
++ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
++ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
++ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
++ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
++ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
++ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
++ ../../ofstd/include/dcmtk/ofstd/oflist.h \
++ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
++ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
++ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
++ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
++ ../../ofstd/include/dcmtk/ofstd/offile.h \
++ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
++ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
++ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
++ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
++ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
++ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
++ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
++ ../../ofstd/include/dcmtk/ofstd/oferror.h \
++ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
++ ../include/dcmtk/dcmdata/dcuid.h ../include/dcmtk/dcmdata/dcdefine.h \
++ ../../oflog/include/dcmtk/oflog/oflog.h \
++ ../../oflog/include/dcmtk/oflog/logger.h \
++ ../../oflog/include/dcmtk/oflog/config.h \
++ ../../oflog/include/dcmtk/oflog/config/defines.h \
++ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
++ ../../oflog/include/dcmtk/oflog/loglevel.h \
++ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
++ ../../oflog/include/dcmtk/oflog/tstring.h \
++ ../../oflog/include/dcmtk/oflog/tchar.h \
++ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
++ ../../oflog/include/dcmtk/oflog/appender.h \
++ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
++ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
++ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
++ ../../oflog/include/dcmtk/oflog/layout.h \
++ ../../oflog/include/dcmtk/oflog/streams.h \
++ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
++ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
++ ../../oflog/include/dcmtk/oflog/spi/filter.h \
++ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
++ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
++ ../../oflog/include/dcmtk/oflog/logmacro.h \
++ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
++ ../../oflog/include/dcmtk/oflog/tracelog.h \
++ ../../ofstd/include/dcmtk/ofstd/oftempf.h \
++ ../include/dcmtk/dcmdata/dcdatset.h ../include/dcmtk/dcmdata/dcitem.h \
++ ../include/dcmtk/dcmdata/dctypes.h ../include/dcmtk/dcmdata/dcobject.h \
++ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
++ ../include/dcmtk/dcmdata/dcerror.h ../include/dcmtk/dcmdata/dcxfer.h \
++ ../include/dcmtk/dcmdata/dcvr.h \
++ ../../ofstd/include/dcmtk/ofstd/ofdeprec.h \
++ ../include/dcmtk/dcmdata/dctag.h ../include/dcmtk/dcmdata/dctagkey.h \
++ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
++ ../include/dcmtk/dcmdata/dcstack.h ../include/dcmtk/dcmdata/dclist.h \
++ ../include/dcmtk/dcmdata/dcpcache.h ../include/dcmtk/dcmdata/dcfilefo.h \
++ ../include/dcmtk/dcmdata/dcsequen.h ../include/dcmtk/dcmdata/dcelem.h \
++ ../include/dcmtk/dcmdata/dcistrmb.h ../include/dcmtk/dcmdata/dcistrma.h \
++ ../include/dcmtk/dcmdata/dcostrmb.h ../include/dcmtk/dcmdata/dcostrma.h \
++ ../include/dcmtk/dcmdata/dcdeftag.h ../include/dcmtk/dcmdata/dcwcache.h \
++ ../include/dcmtk/dcmdata/dcfcache.h
+ tnewdcme.o: tnewdcme.cc ../../config/include/dcmtk/config/osconfig.h \
+  ../../ofstd/include/dcmtk/ofstd/oftest.h \
+  ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+--- dcmtk.orig/dcmdata/tests/Makefile.in
++++ dcmtk/dcmdata/tests/Makefile.in
+@@ -25,7 +25,7 @@
+ 
+ objs = tests.o tpread.o ti2dbmp.o tchval.o tpath.o tvrdatim.o telemlen.o tparser.o \
+ 	tdict.o tvrds.o tvrfd.o tvrui.o tvrol.o tvrov.o tvrsv.o tvruv.o tstrval.o \
+-	tspchrs.o tvrpn.o tparent.o tfilter.o tvrcomp.o tmatch.o tnewdcme.o \
++	tspchrs.o tvrpn.o tparent.o tfilter.o tvrcomp.o tmatch.o tnesting.o tnewdcme.o \
+ 	tgenuid.o tsequen.o titem.o ttag.o txfer.o tbytestr.o tfrmsiz.o
+ 
+ progs = tests
+--- dcmtk.orig/dcmdata/tests/tests.cc
++++ dcmtk/dcmdata/tests/tests.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 2011-2025 OFFIS e.V.
++ *  Copyright (C) 2011-2026 OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -127,5 +127,12 @@
+ OFTEST_REGISTER(dcmdata_xferLookup_4);
+ OFTEST_REGISTER(dcmdata_putOFStringAtPos);
+ OFTEST_REGISTER(dcmdata_uncompressedFrameSize);
++OFTEST_REGISTER(dcmdata_nestingDepthLimit_exceeded);
++OFTEST_REGISTER(dcmdata_nestingDepthLimit_atLimit);
++OFTEST_REGISTER(dcmdata_nestingDepthLimit_wellBelow);
++OFTEST_REGISTER(dcmdata_nestingDepthLimit_customLimit);
++OFTEST_REGISTER(dcmdata_nestingDepthLimit_disabled);
++OFTEST_REGISTER(dcmdata_nestingDepthLimit_datasetAPI);
++OFTEST_REGISTER(dcmdata_nestingDepthLimit_fileFormatAPI);
+ 
+ OFTEST_MAIN("dcmdata")
+--- /dev/null
++++ dcmtk/dcmdata/tests/tnesting.cc
+@@ -0,0 +1,266 @@
++/*
++ *
++ *  Copyright (C) 2026, OFFIS e.V.
++ *  All rights reserved.  See COPYRIGHT file for details.
++ *
++ *  This software and supporting documentation were developed by
++ *
++ *    OFFIS e.V.
++ *    R&D Division Health
++ *    Escherweg 2
++ *    D-26121 Oldenburg, Germany
++ *
++ *
++ *  Module:  dcmdata
++ *
++ *  Author:  Michael Onken
++ *
++ *  Purpose: test program for sequence nesting depth limit
++ *
++ */
++
++
++#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
++
++#include "dcmtk/ofstd/oftest.h"
++#include "dcmtk/ofstd/oftempf.h"
++#include "dcmtk/dcmdata/dcdatset.h"
++#include "dcmtk/dcmdata/dcfilefo.h"
++#include "dcmtk/dcmdata/dcsequen.h"
++#include "dcmtk/dcmdata/dcistrmb.h"
++#include "dcmtk/dcmdata/dcostrmb.h"
++#include "dcmtk/dcmdata/dcerror.h"
++#include "dcmtk/dcmdata/dcdeftag.h"
++#include "dcmtk/dcmdata/dcwcache.h"
++
++
++/** Helper: build a DcmDataset containing a chain of nested sequences to the
++ *  specified depth using the high-level dcmdata API.  Each nesting level
++ *  consists of a DcmSequenceOfItems with one DcmItem, and the innermost
++ *  item is empty.
++ *  @param depth the number of nested sequence levels to generate
++ *  @param dset  output dataset (cleared before use)
++ */
++static void buildNestedDataset(Uint32 depth, DcmDataset& dset)
++{
++    dset.clear();
++    /* start with the dataset as the outermost item */
++    DcmItem* currentItem = &dset;
++    for (Uint32 i = 0; i < depth; ++i)
++    {
++        DcmSequenceOfItems* seq = new DcmSequenceOfItems(DCM_ReferencedSeriesSequence);
++        currentItem->insert(seq);
++        DcmItem* item = new DcmItem();
++        seq->insert(item);
++        currentItem = item;
++    }
++}
++
++
++/** Helper: serialize a dataset to a byte buffer and parse it back using a
++ *  fresh DcmInputStream, with an optional custom nesting depth limit.
++ *  @param srcDset        the dataset to serialize
++ *  @param dstDset        output dataset to receive the parsed result
++ *  @param maxNestingDepth nesting depth setting passed to setMaxNestingDepth():
++ *         0 (default) = compile-time default (DCMTK_MAX_SEQUENCE_NESTING), -1 = unlimited, > 0 = custom limit
++ *  @return the OFCondition returned by DcmDataset::read()
++ */
++static OFCondition serializeAndParse(DcmDataset& srcDset, DcmDataset& dstDset,
++                                     Sint32 maxNestingDepth = 0)
++{
++    /* write the dataset to a memory buffer */
++    const size_t bufLen = 1024 * 1024;
++    Uint8* buf = new Uint8[bufLen];
++
++    DcmOutputBufferStream outStream(buf, bufLen);
++    srcDset.transferInit();
++    DcmWriteCache wcache;
++    OFCondition cond = srcDset.write(outStream, EXS_LittleEndianExplicit, EET_UndefinedLength, &wcache);
++    srcDset.transferEnd();
++    if (cond.bad())
++    {
++        delete[] buf;
++        return cond;
++    }
++    offile_off_t bytesWritten = 0;
++    void* writtenBuf = NULL;
++    outStream.flushBuffer(writtenBuf, bytesWritten);
++
++    /* parse it back with nesting depth limit */
++    DcmInputBufferStream inStream;
++    inStream.setBuffer(buf, bytesWritten);
++    inStream.setEos();
++    inStream.setMaxNestingDepth(maxNestingDepth);
++
++    dstDset.clear();
++    dstDset.transferInit();
++    cond = dstDset.read(inStream, EXS_LittleEndianExplicit);
++    dstDset.transferEnd();
++
++    delete[] buf;
++    return cond;
++}
++
++
++OFTEST(dcmdata_nestingDepthLimit_exceeded)
++{
++    /* One level beyond the default limit (DCMTK_MAX_SEQUENCE_NESTING) must be rejected. */
++    DcmDataset srcDset, dstDset;
++    buildNestedDataset(DCMTK_MAX_SEQUENCE_NESTING + 1, srcDset);
++
++    OFCondition cond = serializeAndParse(srcDset, dstDset);
++    if (cond != EC_NestingDepthLimitExceeded)
++    {
++        OFCHECK_FAIL("Expected EC_NestingDepthLimitExceeded for " << (DCMTK_MAX_SEQUENCE_NESTING + 1)
++            << " levels of nesting, but got: " << cond.text());
++    }
++}
++
++
++OFTEST(dcmdata_nestingDepthLimit_atLimit)
++{
++    /* Exactly DCMTK_MAX_SEQUENCE_NESTING levels must still pass. */
++    DcmDataset srcDset, dstDset;
++    buildNestedDataset(DCMTK_MAX_SEQUENCE_NESTING, srcDset);
++
++    OFCondition cond = serializeAndParse(srcDset, dstDset);
++    if (cond.bad())
++    {
++        OFCHECK_FAIL("Parsing " << DCMTK_MAX_SEQUENCE_NESTING
++            << " levels of nesting should succeed, but got: " << cond.text());
++    }
++}
++
++
++OFTEST(dcmdata_nestingDepthLimit_wellBelow)
++{
++    /* 5 levels of nesting (typical real-world depth) must parse fine. */
++    DcmDataset srcDset, dstDset;
++    buildNestedDataset(5, srcDset);
++
++    OFCondition cond = serializeAndParse(srcDset, dstDset);
++    if (cond.bad())
++    {
++        OFCHECK_FAIL("Parsing 5 levels of nesting should succeed, but got: " << cond.text());
++    }
++}
++
++
++OFTEST(dcmdata_nestingDepthLimit_customLimit)
++{
++    /* Test setMaxNestingDepth(): set the limit to 10.
++     * 10 levels must succeed, 11 levels must fail. */
++    DcmDataset srcDset, dstDset;
++    OFCondition cond;
++
++    buildNestedDataset(10, srcDset);
++    cond = serializeAndParse(srcDset, dstDset, 10);
++    if (cond.bad())
++    {
++        OFCHECK_FAIL("Parsing 10 levels with maxNestingDepth=10 should succeed, but got: " << cond.text());
++    }
++
++    buildNestedDataset(11, srcDset);
++    cond = serializeAndParse(srcDset, dstDset, 10);
++    if (cond != EC_NestingDepthLimitExceeded)
++    {
++        OFCHECK_FAIL("Expected EC_NestingDepthLimitExceeded for 11 levels with maxNestingDepth=10, but got: " << cond.text());
++    }
++}
++
++
++OFTEST(dcmdata_nestingDepthLimit_disabled)
++{
++    /* Test that setMaxNestingDepth(-1) disables the limit entirely.
++     * Even 200 levels of nesting must succeed. */
++    DcmDataset srcDset, dstDset;
++    buildNestedDataset(200, srcDset);
++
++    OFCondition cond = serializeAndParse(srcDset, dstDset, -1);
++    if (cond.bad())
++    {
++        OFCHECK_FAIL("Parsing 200 levels with maxNestingDepth=-1 (unlimited) should succeed, but got: " << cond.text());
++    }
++}
++
++
++/** Helper: create a temporary file path.
++ *  @param tmpFile receives the temporary file path
++ *  @return EC_Normal if successful
++ */
++static OFCondition makeTempFile(OFString& tmpFile)
++{
++    return OFTempFile::createFile(tmpFile, NULL /* fd_out */, O_RDWR,
++        "" /* dir */, "" /* prefix */, ".dcm" /* postfix */);
++}
++
++
++OFTEST(dcmdata_nestingDepthLimit_datasetAPI)
++{
++    /* Test DcmDataset::setMaxNestingDepth() with loadFile(). */
++    DcmDataset srcDset;
++    OFString tmpFile;
++    OFCondition cond;
++
++    /* save as raw dataset (no meta header) */
++    buildNestedDataset(11, srcDset);
++    cond = makeTempFile(tmpFile);
++    OFCHECK(cond.good());
++    cond = srcDset.saveFile(tmpFile, EXS_LittleEndianExplicit);
++    OFCHECK(cond.good());
++
++    /* default limit (DCMTK_MAX_SEQUENCE_NESTING): 11 levels should succeed */
++    DcmDataset dset1;
++    cond = dset1.loadFile(tmpFile, EXS_LittleEndianExplicit);
++    if (cond.bad())
++    {
++        OFCHECK_FAIL("DcmDataset::loadFile() with 11 levels should succeed with default limit, but got: " << cond.text());
++    }
++
++    /* custom limit 10: 11 levels should fail */
++    DcmDataset dset2;
++    dset2.setMaxNestingDepth(10);
++    cond = dset2.loadFile(tmpFile, EXS_LittleEndianExplicit);
++    if (cond != EC_NestingDepthLimitExceeded)
++    {
++        OFCHECK_FAIL("DcmDataset::loadFile() with 11 levels and maxNestingDepth=10 should fail, but got: " << cond.text());
++    }
++
++    OFStandard::deleteFile(tmpFile);
++}
++
++
++OFTEST(dcmdata_nestingDepthLimit_fileFormatAPI)
++{
++    /* Test DcmFileFormat::setMaxNestingDepth() with loadFile(). */
++    DcmDataset srcDset;
++    OFString tmpFile;
++    OFCondition cond;
++
++    /* save as DcmFileFormat (with meta header) */
++    buildNestedDataset(11, srcDset);
++    cond = makeTempFile(tmpFile);
++    OFCHECK(cond.good());
++    DcmFileFormat srcFF(&srcDset);
++    cond = srcFF.saveFile(tmpFile, EXS_LittleEndianExplicit);
++    OFCHECK(cond.good());
++
++    /* default limit (DCMTK_MAX_SEQUENCE_NESTING): 11 levels should succeed */
++    DcmFileFormat ff1;
++    cond = ff1.loadFile(tmpFile);
++    if (cond.bad())
++    {
++        OFCHECK_FAIL("DcmFileFormat::loadFile() with 11 levels should succeed with default limit, but got: " << cond.text());
++    }
++
++    /* custom limit 10: 11 levels should fail */
++    DcmFileFormat ff2;
++    ff2.setMaxNestingDepth(10);
++    cond = ff2.loadFile(tmpFile);
++    if (cond != EC_NestingDepthLimitExceeded)
++    {
++        OFCHECK_FAIL("DcmFileFormat::loadFile() with 11 levels and maxNestingDepth=10 should fail, but got: " << cond.text());
++    }
++
++    OFStandard::deleteFile(tmpFile);
++}
+--- dcmtk.orig/dcmnet/include/dcmtk/dcmnet/scp.h
++++ dcmtk/dcmnet/include/dcmtk/dcmnet/scp.h
+@@ -360,6 +360,17 @@
+      */
+     void setAlwaysAcceptDefaultRole(const OFBool enabled);
+ 
++    /** Set the maximum permitted sequence nesting depth for parsing
++     *  datasets received over the network. This limit is applied to
++     *  each dataset received via receiveDIMSEDataset().
++     *  - Value 0 (default): apply the compile-time default
++     *    (DCMTK_MAX_SEQUENCE_NESTING)
++     *  - Value -1: disable the check (allow unlimited nesting)
++     *  - Value > 0: use this value as the maximum nesting depth
++     *  @param maxDepth maximum nesting depth setting
++     */
++    void setMaxNestingDepth(const Sint32 maxDepth);
++
+     /* Get methods for SCP settings */
+ 
+     /** Returns TCP/IP port number SCP listens for new connection requests
+@@ -434,6 +445,14 @@
+      */
+     OFBool getProgressNotificationMode() const;
+ 
++    /** Return the maximum permitted sequence nesting depth for
++     *  parsing datasets received over the network.
++     *  @return maximum nesting depth setting
++     *    (0 = compile-time default DCMTK_MAX_SEQUENCE_NESTING,
++     *    -1 = unlimited)
++     */
++    Sint32 getMaxNestingDepth() const;
++
+     /** Get access to the configuration of the SCP. Note that the functionality
+      *  on the configuration object is shadowed by other API functions of DcmSCP.
+      *  The existing functions are provided in order to not break users of this
+@@ -1157,6 +1176,11 @@
+     /// it, e.g. in the context of the DcmSCPPool class.
+     DcmSharedSCPConfig m_cfg;
+ 
++    /// Maximum sequence nesting depth for parsing received datasets
++    /// (0 = compile-time default DCMTK_MAX_SEQUENCE_NESTING,
++    /// -1 = unlimited)
++    Sint32 m_maxNestingDepth;
++
+     /** Drops association and clears internal structures to free memory
+      */
+     void dropAndDestroyAssociation();
+--- dcmtk.orig/dcmnet/include/dcmtk/dcmnet/scu.h
++++ dcmtk/dcmnet/include/dcmtk/dcmnet/scu.h
+@@ -739,6 +739,17 @@
+      */
+     void setProgressNotificationMode(const OFBool mode);
+ 
++    /** Set the maximum permitted sequence nesting depth for parsing
++     *  datasets received over the network. This limit is applied to
++     *  each dataset received via receiveDIMSEDataset().
++     *  - Value 0 (default): apply the compile-time default
++     *    (DCMTK_MAX_SEQUENCE_NESTING)
++     *  - Value -1: disable the check (allow unlimited nesting)
++     *  - Value > 0: use this value as the maximum nesting depth
++     *  @param maxDepth maximum nesting depth setting
++     */
++    void setMaxNestingDepth(const Sint32 maxDepth);
++
+     /* Get methods */
+ 
+     /** Get current connection status
+@@ -831,6 +842,14 @@
+      */
+     OFBool getProgressNotificationMode() const;
+ 
++    /** Return the maximum permitted sequence nesting depth for
++     *  parsing datasets received over the network.
++     *  @return maximum nesting depth setting
++     *    (0 = compile-time default DCMTK_MAX_SEQUENCE_NESTING,
++     *    -1 = unlimited)
++     */
++    Sint32 getMaxNestingDepth() const;
++
+     /** Returns whether SCU is configured to create a TLS connection with the SCP
+      *  @return OFTrue if TLS mode has been enabled, OFFalse otherwise
+      */
+@@ -1136,6 +1155,11 @@
+     /// Progress notification mode (default: enabled)
+     OFBool m_progressNotificationMode;
+ 
++    /// Maximum sequence nesting depth for parsing received datasets
++    /// (0 = compile-time default DCMTK_MAX_SEQUENCE_NESTING,
++    /// -1 = unlimited)
++    Sint32 m_maxNestingDepth;
++
+     /// Flag indicating whether secure mode has been enabled (default: disabled)
+     OFBool m_secureConnectionEnabled;
+ 
+--- dcmtk.orig/dcmnet/libsrc/dimse.cc
++++ dcmtk/dcmnet/libsrc/dimse.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2025, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were partly developed by
+@@ -1536,7 +1536,8 @@
+         dset = *dataObject;
+     }
+ 
+-    /* check if there is still no DcmDataset object which can be used to store the data set. */
++    /* check if there is still no DcmDataset object (i.e. if allocation fails) */
++    /* which can be used to store the data set. */
+     if (dset == NULL)
+     {
+         /* if this is the case, just go ahead an receive data, but do not store it anywhere */
+--- dcmtk.orig/dcmnet/libsrc/scp.cc
++++ dcmtk/dcmnet/libsrc/scp.cc
+@@ -32,6 +32,7 @@
+ : m_network(NULL)
+ , m_assoc(NULL)
+ , m_cfg()
++, m_maxNestingDepth(0)
+ {
+     OFStandard::initializeNetwork();
+ }
+@@ -1590,6 +1591,19 @@
+     if (m_assoc == NULL)
+         return DIMSE_ILLEGALASSOCIATION;
+ 
++    /* if a custom nesting depth limit is configured, pre-allocate
++     * the dataset and apply the setting before parsing starts.
++     * DIMSE_receiveDataSetInMemory() will use this dataset instead
++     * of creating a new one internally. */
++    OFBool weAllocated = OFFalse;
++    if (dataObject != NULL && *dataObject == NULL
++        && m_maxNestingDepth != 0)
++    {
++        *dataObject = new DcmDataset();
++        (*dataObject)->setMaxNestingDepth(m_maxNestingDepth);
++        weAllocated = OFTrue;
++    }
++
+     OFCondition cond;
+     /* call the corresponding DIMSE function to receive the dataset */
+     if (m_cfg->getProgressNotificationMode())
+@@ -1619,6 +1633,14 @@
+     }
+     else
+     {
++        /* if we pre-allocated the dataset, clean up on error since
++         * DIMSE_receiveDataSetInMemory() won't delete a dataset
++         * that was passed in by the caller */
++        if (weAllocated && dataObject != NULL)
++        {
++            delete *dataObject;
++            *dataObject = NULL;
++        }
+         OFString tempStr;
+         DCMNET_ERROR("Unable to receive dataset on presentation context "
+                      << OFstatic_cast(unsigned int, *presID) << ": " << DimseCondition::dump(tempStr, cond));
+@@ -1910,6 +1932,13 @@
+ 
+ // ----------------------------------------------------------------------------
+ 
++void DcmSCP::setMaxNestingDepth(const Sint32 maxDepth)
++{
++    m_maxNestingDepth = maxDepth;
++}
++
++// ----------------------------------------------------------------------------
++
+ /* Get methods for SCP settings and current association information */
+ 
+ OFBool DcmSCP::getRefuseAssociation() const
+@@ -2002,6 +2031,13 @@
+ }
+ 
+ // ----------------------------------------------------------------------------
++
++Sint32 DcmSCP::getMaxNestingDepth() const
++{
++    return m_maxNestingDepth;
++}
++
++// ----------------------------------------------------------------------------
+ 
+ OFBool DcmSCP::isConnected() const
+ {
+--- dcmtk.orig/dcmnet/libsrc/scu.cc
++++ dcmtk/dcmnet/libsrc/scu.cc
+@@ -56,6 +56,7 @@
+     , m_verbosePCMode(OFFalse)
+     , m_datasetConversionMode(OFFalse)
+     , m_progressNotificationMode(OFTrue)
++    , m_maxNestingDepth(0)
+     , m_secureConnectionEnabled(OFFalse)
+     , m_protocolVersion(ASC_AF_Default)
+ {
+@@ -2500,6 +2501,19 @@
+     if (!isConnected())
+         return DIMSE_ILLEGALASSOCIATION;
+ 
++    /* if a custom nesting depth limit is configured, pre-allocate
++     * the dataset and apply the setting before parsing starts.
++     * DIMSE_receiveDataSetInMemory() will use this dataset instead
++     * of creating a new one internally. */
++    OFBool weAllocated = OFFalse;
++    if (dataObject != NULL && *dataObject == NULL
++        && m_maxNestingDepth != 0)
++    {
++        *dataObject = new DcmDataset();
++        (*dataObject)->setMaxNestingDepth(m_maxNestingDepth);
++        weAllocated = OFTrue;
++    }
++
+     OFCondition cond;
+     /* call the corresponding DIMSE function to receive the dataset */
+     if (m_progressNotificationMode)
+@@ -2519,6 +2533,14 @@
+     }
+     else
+     {
++        /* if we pre-allocated the dataset, clean up on error since
++         * DIMSE_receiveDataSetInMemory() won't delete a dataset
++         * that was passed in by the caller */
++        if (weAllocated && dataObject != NULL)
++        {
++            delete *dataObject;
++            *dataObject = NULL;
++        }
+         OFString tempStr;
+         DCMNET_ERROR("Unable to receive dataset on presentation context "
+                      << OFstatic_cast(unsigned int, *presID) << ": " << DimseCondition::dump(tempStr, cond));
+@@ -2607,6 +2629,11 @@
+     m_progressNotificationMode = mode;
+ }
+ 
++void DcmSCU::setMaxNestingDepth(const Sint32 maxDepth)
++{
++    m_maxNestingDepth = maxDepth;
++}
++
+ void DcmSCU::setProtocolVersion(T_ASC_ProtocolFamily protocolVersion)
+ {
+     m_protocolVersion = protocolVersion;
+@@ -2694,6 +2721,11 @@
+     return m_progressNotificationMode;
+ }
+ 
++Sint32 DcmSCU::getMaxNestingDepth() const
++{
++    return m_maxNestingDepth;
++}
++
+ OFCondition DcmSCU::getDatasetInfo(DcmDataset* dataset,
+                                    OFString& sopClassUID,
+                                    OFString& sopInstanceUID,
+--- dcmtk.orig/dcmnet/tests/tests.cc
++++ dcmtk/dcmnet/tests/tests.cc
+@@ -51,6 +51,11 @@
+ OFTEST_REGISTER(dcmnet_scu_sendNSETRequest_succeeds_and_modifies_instance_when_scp_has_instance);
+ OFTEST_REGISTER(dcmnet_scu_sendNSETRequest_succeeds_and_sets_responsestatuscode_from_scp_when_scp_sets_error_status);
+ 
++OFTEST_REGISTER(dcmnet_scp_maxNestingDepth_getset);
++OFTEST_REGISTER(dcmnet_scu_maxNestingDepth_getset);
++OFTEST_REGISTER(dcmnet_scp_maxNestingDepth_rejects_deep);
++OFTEST_REGISTER(dcmnet_scp_maxNestingDepth_accepts_shallow);
++
+ #endif // WITH_THREADS
+ 
+ OFTEST_MAIN("dcmnet")
+--- dcmtk.orig/dcmnet/tests/tscuscp.cc
++++ dcmtk/dcmnet/tests/tscuscp.cc
+@@ -1113,4 +1113,209 @@
+ }
+ 
+ 
++// Test that setMaxNestingDepth/getMaxNestingDepth work on DcmSCP
++OFTEST(dcmnet_scp_maxNestingDepth_getset)
++{
++    DcmSCP scp;
++    // Default must be 0 (use compile-time default)
++    OFCHECK_EQUAL(scp.getMaxNestingDepth(), 0);
++    scp.setMaxNestingDepth(10);
++    OFCHECK_EQUAL(scp.getMaxNestingDepth(), 10);
++    scp.setMaxNestingDepth(-1);
++    OFCHECK_EQUAL(scp.getMaxNestingDepth(), -1);
++    scp.setMaxNestingDepth(0);
++    OFCHECK_EQUAL(scp.getMaxNestingDepth(), 0);
++}
++
++
++// Test that setMaxNestingDepth/getMaxNestingDepth work on DcmSCU
++OFTEST(dcmnet_scu_maxNestingDepth_getset)
++{
++    DcmSCU scu;
++    // Default must be 0 (use compile-time default)
++    OFCHECK_EQUAL(scu.getMaxNestingDepth(), 0);
++    scu.setMaxNestingDepth(5);
++    OFCHECK_EQUAL(scu.getMaxNestingDepth(), 5);
++    scu.setMaxNestingDepth(-1);
++    OFCHECK_EQUAL(scu.getMaxNestingDepth(), -1);
++    scu.setMaxNestingDepth(0);
++    OFCHECK_EQUAL(scu.getMaxNestingDepth(), 0);
++}
++
++
++/** Helper: build a DcmDataset with nested sequences to a given depth.
++ *  @param depth number of nesting levels
++ *  @param dset  output dataset (cleared before use)
++ */
++static void buildNestedDataset(Uint32 depth, DcmDataset& dset)
++{
++    dset.clear();
++    DcmItem* currentItem = &dset;
++    for (Uint32 i = 0; i < depth; ++i)
++    {
++        DcmSequenceOfItems* sq =
++            new DcmSequenceOfItems(DCM_ReferencedSeriesSequence);
++        currentItem->insert(sq);
++        DcmItem* item = new DcmItem();
++        sq->insert(item);
++        currentItem = item;
++    }
++}
++
++
++/** SCP that applies a nesting depth limit and records whether
++ *  receiving the dataset succeeded or failed.
++ */
++struct NestingTestSCP : TestSCP
++{
++    NestingTestSCP(Sint32 maxNesting)
++        : TestSCP()
++        , m_receiveResult(EC_NotYetImplemented)
++    {
++        setMaxNestingDepth(maxNesting);
++        DcmSCPConfig& config = getConfig();
++        config.setAETitle("NESTING_SCP");
++        config.setConnectionBlockingMode(DUL_NOBLOCK);
++        config.setConnectionTimeout(10);
++        config.setHostLookupEnabled(OFFalse);
++        config.setPort(0);
++        OFList<OFString> xfers;
++        xfers.push_back(UID_LittleEndianImplicitTransferSyntax);
++        OFCHECK(config.addPresentationContext(
++            UID_ModalityPerformedProcedureStepSOPClass, xfers).good());
++        OFCHECK(openListenPort().good());
++        m_portNum = config.getPort();
++    }
++
++    OFCondition handleIncomingCommand(
++        T_DIMSE_Message* incomingMsg,
++        const DcmPresentationContextInfo& presInfo)
++    {
++        if (incomingMsg->CommandField == DIMSE_N_CREATE_RQ)
++        {
++            T_DIMSE_N_CreateRQ& req = incomingMsg->msg.NCreateRQ;
++            if (req.DataSetType != DIMSE_DATASET_NULL)
++            {
++                DcmDataset* dataset = OFnullptr;
++                T_ASC_PresentationContextID presIDdset;
++                m_receiveResult =
++                    receiveDIMSEDataset(&presIDdset, &dataset);
++                /* send a response regardless of receive outcome */
++                T_DIMSE_Message rsp;
++                memset(&rsp, 0, sizeof(rsp));
++                rsp.CommandField = DIMSE_N_CREATE_RSP;
++                T_DIMSE_N_CreateRSP& createRsp = rsp.msg.NCreateRSP;
++                createRsp.MessageIDBeingRespondedTo = req.MessageID;
++                createRsp.DimseStatus = m_receiveResult.good()
++                    ? STATUS_N_Success
++                    : STATUS_N_ProcessingFailure;
++                createRsp.DataSetType = DIMSE_DATASET_NULL;
++                OFStandard::strlcpy(
++                    createRsp.AffectedSOPClassUID,
++                    req.AffectedSOPClassUID,
++                    sizeof(createRsp.AffectedSOPClassUID));
++                createRsp.opts = O_NCREATE_AFFECTEDSOPCLASSUID;
++                sendDIMSEMessage(
++                    presInfo.presentationContextID, &rsp, NULL);
++                delete dataset;
++            }
++            return EC_Normal;
++        }
++        return DcmSCP::handleIncomingCommand(incomingMsg, presInfo);
++    }
++
++    /// Result of receiveDIMSEDataset() for the last request
++    OFCondition m_receiveResult;
++    /// Port the SCP is listening on
++    Uint16 m_portNum;
++};
++
++
++// Test that SCP's nesting depth limit rejects deeply nested data
++// received over the network
++OFTEST_FLAGS(dcmnet_scp_maxNestingDepth_rejects_deep, EF_Slow)
++{
++    NestingTestSCP scp(3);
++    scp.m_set_stop_after_assoc = OFTrue;
++    scp.start();
++    OFStandard::forceSleep(1);
++
++    // SCU sends a dataset with 4 levels of nesting (exceeds limit 3)
++    DcmSCU scu;
++    scu.setAETitle("NESTING_SCU");
++    scu.setPeerAETitle("NESTING_SCP");
++    scu.setPeerHostName("localhost");
++    scu.setPeerPort(scp.m_portNum);
++    OFList<OFString> xfers;
++    xfers.push_back(UID_LittleEndianImplicitTransferSyntax);
++    OFCHECK(scu.addPresentationContext(
++        UID_ModalityPerformedProcedureStepSOPClass, xfers).good());
++    OFCHECK(scu.initNetwork().good());
++    OFCHECK(scu.negotiateAssociation().good());
++
++    DcmDataset reqDataset;
++    buildNestedDataset(4, reqDataset);
++    T_ASC_PresentationContextID presID = scu.findPresentationContextID(
++        UID_ModalityPerformedProcedureStepSOPClass,
++        UID_LittleEndianImplicitTransferSyntax);
++    OFCHECK(presID != 0);
++    Uint16 rspStatus = 0;
++    DcmDataset* rspDataset = NULL;
++    scu.sendNCREATERequest(presID, "1.2.3.4.5",
++        &reqDataset, rspDataset, rspStatus);
++    delete rspDataset;
++    if (scu.isConnected())
++        scu.releaseAssociation();
++    OFStandard::forceSleep(2);
++    scp.join();
++
++    // Verify SCP saw the nesting depth error
++    OFCHECK(scp.m_receiveResult == DIMSE_RECEIVEFAILED);
++}
++
++
++// Test that SCP's nesting depth limit accepts data within the limit
++OFTEST_FLAGS(dcmnet_scp_maxNestingDepth_accepts_shallow, EF_Slow)
++{
++    NestingTestSCP scp(3);
++    scp.m_set_stop_after_assoc = OFTrue;
++    scp.start();
++    OFStandard::forceSleep(1);
++
++    // SCU sends a dataset with 3 levels of nesting (at the limit)
++    DcmSCU scu;
++    scu.setAETitle("NESTING_SCU");
++    scu.setPeerAETitle("NESTING_SCP");
++    scu.setPeerHostName("localhost");
++    scu.setPeerPort(scp.m_portNum);
++    OFList<OFString> xfers;
++    xfers.push_back(UID_LittleEndianImplicitTransferSyntax);
++    OFCHECK(scu.addPresentationContext(
++        UID_ModalityPerformedProcedureStepSOPClass, xfers).good());
++    OFCHECK(scu.initNetwork().good());
++    OFCHECK(scu.negotiateAssociation().good());
++
++    DcmDataset reqDataset;
++    buildNestedDataset(3, reqDataset);
++    T_ASC_PresentationContextID presID = scu.findPresentationContextID(
++        UID_ModalityPerformedProcedureStepSOPClass,
++        UID_LittleEndianImplicitTransferSyntax);
++    OFCHECK(presID != 0);
++    Uint16 rspStatus = 0;
++    DcmDataset* rspDataset = NULL;
++    OFCondition result = scu.sendNCREATERequest(presID, "1.2.3.4.5",
++        &reqDataset, rspDataset, rspStatus);
++    OFCHECK_MSG(result.good(), result.text());
++    OFCHECK(rspStatus == STATUS_N_Success);
++    delete rspDataset;
++    if (scu.isConnected())
++        OFCHECK(scu.releaseAssociation().good());
++    OFStandard::forceSleep(2);
++    scp.join();
++
++    // Verify SCP successfully received the dataset
++    OFCHECK(scp.m_receiveResult.good());
++}
++
++
+ #endif // WITH_THREADS


=====================================
debian/patches/CVE-2026-5663.patch
=====================================
@@ -0,0 +1,232 @@
+Applied-Upstream: edbb085e45788dccaf0e64d71534cfca925784b8
+Author: Marco Eichelberg <eichelberg at offis.de>
+Last-Update: 2026-03-21
+Description: Sanitize all strings passed to the exec options.
+ Sanitize the text fields from incoming DICOM associations and DICOM objects
+ (such as Study Instance UID, SOP Instance UID, Patient's Name) and the
+ calling SCU's network presentation address by removing special characters
+ that may be interpreted as shell escape characters when one of the
+ execution options (e.g. --exec-on-reception) is in use.
+ .
+ Thanks to Machine Spirits UG (haftungsbeschränkt) for the bug report,
+ detailed analysis and proof of concept.
+ .
+ This closes DCMTK issue #1194.
+Bug: https://support.dcmtk.org/redmine/issues/1194
+Bug-Debian: https://bugs.debian.org/1133001
+Reviewed-By: Étienne Mollier <emollier at debian.org>
+
+--- dcmtk.orig/dcmnet/apps/storescp.cc
++++ dcmtk/dcmnet/apps/storescp.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2025, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -1601,7 +1601,9 @@
+     calledAETitle.clear();
+   }
+   // store calling presentation address (i.e. remote hostname)
+-  callingPresentationAddress = OFSTRING_GUARD(assoc->params->DULparams.callingPresentationAddress);
++  callingPresentationAddress = "\"";
++  callingPresentationAddress += OFSTRING_GUARD(assoc->params->DULparams.callingPresentationAddress);
++  callingPresentationAddress += "\"";
+ 
+   /* now do the real work, i.e. receive DIMSE commands over the network connection */
+   /* which was established and handle these commands correspondingly. In case of */
+@@ -1965,6 +1967,7 @@
+             dateTime.getTime().getHour(), dateTime.getTime().getMinute(), dateTime.getTime().getIntSecond(), dateTime.getTime().getMilliSecond());
+ 
+           OFString subdirectoryName;
++          OFString s;
+           switch (opt_sortStudyMode)
+           {
+             case ESM_Timestamp:
+@@ -1979,15 +1982,27 @@
+               subdirectoryName = opt_sortStudyDirPrefix;
+               if (!subdirectoryName.empty())
+                 subdirectoryName += '_';
+-              subdirectoryName += currentStudyInstanceUID;
+-              OFStandard::sanitizeFilename(subdirectoryName);
++              s = currentStudyInstanceUID;
++              OFStandard::sanitizeFilename(s);
++              if (s != currentStudyInstanceUID)
++              {
++                OFLOG_WARN(storescpLogger, "Sanitized unusual characters in Study Instance UID, converted from \"" << currentStudyInstanceUID << "\" to \"" << s << "\".");
++              }
++              subdirectoryName += s;
+               break;
+             case ESM_PatientName:
+               // pattern: "[Patient's Name]_[YYYYMMDD]_[HHMMSSMMM]"
+               subdirectoryName = currentPatientName;
++              OFStandard::sanitizeFilename(subdirectoryName);
++              if (subdirectoryName != currentPatientName)
++              {
++                // It is quite normal that we need to sanitize characters in PatientName.
++                // Therefore, this is only a debug message and not a warning, unlike the other
++                // messages about sanitized fields, which are normally not expected.
++                OFLOG_DEBUG(storescpLogger, "Sanitized characters in Patient Name, converted from \"" << currentPatientName << "\" to \"" << subdirectoryName << "\".");
++              }
+               subdirectoryName += '_';
+               subdirectoryName += timestamp;
+-              OFStandard::sanitizeFilename(subdirectoryName);
+               break;
+             case ESM_None:
+               break;
+@@ -2196,8 +2211,13 @@
+     else
+     {
+       // Use the SOP instance UID as found in the C-STORE request message as part of the filename
+-      OFString uid(OFSTRING_GUARD(req->AffectedSOPInstanceUID));
++      OFString s(OFSTRING_GUARD(req->AffectedSOPInstanceUID));
++      OFString uid = s;
+       OFStandard::sanitizeFilename(uid);
++      if (uid != s)
++      {
++        OFLOG_WARN(storescpLogger, "Sanitized unusual characters in SOP Instance UID, converted from \"" << s << "\" to \"" << uid << "\".");
++      }
+       OFStandard::snprintf(imageFileName, sizeof(imageFileName), "%s%c%s.%s%s", opt_outputDirectory.c_str(), PATH_SEPARATOR, dcmSOPClassUIDToModality(req->AffectedSOPClassUID, "UNKNOWN"),
+         uid.c_str(), opt_fileNameExtension.c_str());
+     }
+@@ -2367,16 +2387,19 @@
+   if( !opt_ignore )
+   {
+     // perform substitution for placeholder #p (depending on presence of any --sort-xxx option)
++    // Note: We do not enclose this in quotes because it may be used as part of a path expression.
+     OFString dir = (opt_sortStudyMode == ESM_None) ? opt_outputDirectory : subdirectoryPathAndName;
+     cmd = replaceChars( cmd, OFString(PATH_PLACEHOLDER), dir );
+ 
+     // perform substitution for placeholder #f; note that outputFileNameArray.back()
+     // always contains the name of the file (without path) which was written last.
++    // Note: We do not enclose this in quotes because it may be used as part of a path expression.
+     OFString outputFileName = outputFileNameArray.back();
+     cmd = replaceChars( cmd, OFString(FILENAME_PLACEHOLDER), outputFileName );
+   }
+ 
+-  // perform substitution for placeholder #a
++  // perform substitution for placeholder #a.
++  // Note that this string is already enclosed in double quotes at this point
+   s = callingAETitle;
+   sanitizeAETitle(s);
+   if (s != callingAETitle)
+@@ -2385,7 +2408,8 @@
+   }
+   cmd = replaceChars( cmd, OFString(CALLING_AETITLE_PLACEHOLDER), s );
+ 
+-  // perform substitution for placeholder #c
++  // perform substitution for placeholder #c.
++  // Note that this string is already enclosed in double quotes at this point
+   s = calledAETitle;
+   sanitizeAETitle(s);
+   if (s != calledAETitle)
+@@ -2394,8 +2418,15 @@
+   }
+   cmd = replaceChars( cmd, OFString(CALLED_AETITLE_PLACEHOLDER), s );
+ 
+-  // perform substitution for placeholder #r
+-  cmd = replaceChars( cmd, OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), callingPresentationAddress );
++  // perform substitution for placeholder #r.
++  // Note that this string is already enclosed in double quotes at this point
++  s = callingPresentationAddress;
++  sanitizeAETitle(s);
++  if (s != callingPresentationAddress)
++  {
++    OFLOG_WARN(storescpLogger, "Sanitized unusual characters in calling presentation address, converted from " << callingPresentationAddress << " to " << s << ".");
++  }
++  cmd = replaceChars( cmd, OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), s );
+ 
+   // Execute command in a new process
+   executeCommand( cmd );
+@@ -2500,20 +2531,38 @@
+   OFString s;
+ 
+   // perform substitution for placeholder #p; #p will be substituted by lastStudySubdirectoryPathAndName
++  // Note: We do not enclose this in quotes because it may be used as part of a path expression.
+   cmd = replaceChars( cmd, OFString(PATH_PLACEHOLDER), lastStudySubdirectoryPathAndName );
+ 
+-  // perform substitution for placeholder #a
++  // perform substitution for placeholder #a.
++  // Note that this string is already enclosed in double quotes at this point
+   s = callingAETitle;
+   sanitizeAETitle(s);
++  if (s != callingAETitle)
++  {
++    OFLOG_WARN(storescpLogger, "Sanitized unusual characters in calling aetitle, converted from " << callingAETitle << " to " << s << ".");
++  }
+   cmd = replaceChars( cmd, OFString(CALLING_AETITLE_PLACEHOLDER), s );
+ 
+-  // perform substitution for placeholder #c
++  // perform substitution for placeholder #c.
++  // Note that this string is already enclosed in double quotes at this point
+   s = calledAETitle;
+   sanitizeAETitle(s);
++  if (s != calledAETitle)
++  {
++    OFLOG_WARN(storescpLogger, "Sanitized unusual characters in called aetitle, converted from " << calledAETitle << " to " << s << ".");
++  }
+   cmd = replaceChars( cmd, OFString(CALLED_AETITLE_PLACEHOLDER), s );
+ 
+-  // perform substitution for placeholder #r
+-  cmd = replaceChars( cmd, OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), callingPresentationAddress );
++  // perform substitution for placeholder #r.
++  // Note that this string is already enclosed in double quotes at this point
++  s = callingPresentationAddress;
++  sanitizeAETitle(s);
++  if (s != callingPresentationAddress)
++  {
++    OFLOG_WARN(storescpLogger, "Sanitized unusual characters in calling presentation address, converted from " << callingPresentationAddress << " to " << s << ".");
++  }
++  cmd = replaceChars( cmd, OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), s );
+ 
+   // Execute command in a new process
+   executeCommand( cmd );
+--- dcmtk.orig/ofstd/libsrc/ofstd.cc
++++ dcmtk/ofstd/libsrc/ofstd.cc
+@@ -3402,16 +3402,26 @@
+ }
+ 
+ 
++static const char sanitized_filename_charset[] =
++{
++  ' ', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '-', '.', '_',
++  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '_', '_', '_', '_', '_',
++  '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
++  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '_', '_', '_', '_',
++  '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
++  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_', '_', '_', '_', '_'
++};
++
++
+ void OFStandard::sanitizeFilename(OFString& fname)
+ {
+     const size_t len = fname.length();
++    char c;
+     for (size_t i = 0; i < len; ++i)
+     {
+-#ifdef _WIN32
+-        if ((fname[i] == PATH_SEPARATOR) || (fname[i] == '/')) fname[i] = '_';
+-#else
+-        if (fname[i] == PATH_SEPARATOR) fname[i] = '_';
+-#endif
++        c = fname[i];
++        if (c != 0 && (c < 32 || c >= 127)) c = '_'; else c = sanitized_filename_charset[c-32];
++        fname[i] = c;
+     }
+ }
+ 
+@@ -3423,11 +3433,7 @@
+         char *c = fname;
+         while (*c)
+         {
+-#ifdef _WIN32
+-            if ((*c == PATH_SEPARATOR) || (*c == '/')) *c = '_';
+-#else
+-            if (*c == PATH_SEPARATOR) *c = '_';
+-#endif
++            if (*c < 32 || *c >= 127) *c = '_'; else *c = sanitized_filename_charset[*c-32];
+             ++c;
+         }
+     }


=====================================
debian/patches/series
=====================================
@@ -4,3 +4,5 @@
 remove_version.patch
 skip-bigendian-roundtrip-failure.patch
 hurd.patch
+CVE-2026-5663.patch
+CVE-2026-10528-partial.patch



View it on GitLab: https://salsa.debian.org/med-team/dcmtk/-/compare/75d16836bb16e7201d8cfcabc0dff63de0e3022f...90494a582dc815b0ef66423282e0a3211a5e5f80

-- 
View it on GitLab: https://salsa.debian.org/med-team/dcmtk/-/compare/75d16836bb16e7201d8cfcabc0dff63de0e3022f...90494a582dc815b0ef66423282e0a3211a5e5f80
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20260603/2f35ff83/attachment-0001.htm>


More information about the debian-med-commit mailing list