view OrthancFramework/Resources/Patches/dcmtk-3.7.0-max-nested-sequence.patch @ 7144:a2cd12438c41 default tip

fix comment
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 31 Aug 2026 09:16:01 +0200
parents bae99026ca97
children
line wrap: on
line source

Only in dcmtk-3.7.0/: .gitignore
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/config/docs/macros.txt dcmtk-3.7.0/config/docs/macros.txt
--- dcmtk-3.7.0.orig/config/docs/macros.txt	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/config/docs/macros.txt	2026-05-06 10:47:14.137800800 +0200
@@ -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
Only in dcmtk-3.7.0.orig/config/include/dcmtk/config: osconfig.h
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcerror.h dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcerror.h
--- dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcerror.h	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcerror.h	2026-05-06 10:47:14.137800800 +0200
@@ -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;
 
 ///@}
 
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcfilefo.h dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcfilefo.h
--- dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcfilefo.h	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcfilefo.h	2026-05-06 10:47:14.137800800 +0200
@@ -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; }
 };
 
 
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcistrma.h dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcistrma.h
--- dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcistrma.h	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcistrma.h	2026-05-06 10:47:14.137800800 +0200
@@ -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_;
 };
 
 
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcitem.h dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcitem.h
--- dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcitem.h	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcitem.h	2026-05-06 10:47:14.137800800 +0200
@@ -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
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcobject.h dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcobject.h
--- dcmtk-3.7.0.orig/dcmdata/include/dcmtk/dcmdata/dcobject.h	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/include/dcmtk/dcmdata/dcobject.h	2026-05-06 10:47:14.137800800 +0200
@@ -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;
 
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/libsrc/dcdatset.cc dcmtk-3.7.0/dcmdata/libsrc/dcdatset.cc
--- dcmtk-3.7.0.orig/dcmdata/libsrc/dcdatset.cc	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/libsrc/dcdatset.cc	2026-05-06 10:47:14.141581926 +0200
@@ -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();
Only in dcmtk-3.7.0.orig/dcmdata/libsrc: dcdict_orthanc.cc
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/libsrc/dcerror.cc dcmtk-3.7.0/dcmdata/libsrc/dcerror.cc
--- dcmtk-3.7.0.orig/dcmdata/libsrc/dcerror.cc	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/libsrc/dcerror.cc	2026-05-06 10:47:14.141581926 +0200
@@ -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;
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/libsrc/dcfilefo.cc dcmtk-3.7.0/dcmdata/libsrc/dcfilefo.cc
--- dcmtk-3.7.0.orig/dcmdata/libsrc/dcfilefo.cc	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/libsrc/dcfilefo.cc	2026-05-06 10:48:15.265234129 +0200
@@ -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,8 +131,8 @@
     FileReadMode = obj.FileReadMode;
     ImplementationClassUID = obj.ImplementationClassUID;
     ImplementationVersionName = obj.ImplementationVersionName;
+        MaxNestingDepth = obj.MaxNestingDepth;
   }
-
   return *this;
 }
 
@@ -942,6 +945,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 +978,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();
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/libsrc/dcistrma.cc dcmtk-3.7.0/dcmdata/libsrc/dcistrma.cc
--- dcmtk-3.7.0.orig/dcmdata/libsrc/dcistrma.cc	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/libsrc/dcistrma.cc	2026-05-06 10:47:14.141581926 +0200
@@ -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;
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/libsrc/dcitem.cc dcmtk-3.7.0/dcmdata/libsrc/dcitem.cc
--- dcmtk-3.7.0.orig/dcmdata/libsrc/dcitem.cc	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/libsrc/dcitem.cc	2026-05-06 10:47:14.141581926 +0200
@@ -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 */
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmdata/libsrc/dcsequen.cc dcmtk-3.7.0/dcmdata/libsrc/dcsequen.cc
--- dcmtk-3.7.0.orig/dcmdata/libsrc/dcsequen.cc	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmdata/libsrc/dcsequen.cc	2026-05-06 10:47:14.141581926 +0200
@@ -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());
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmnet/include/dcmtk/dcmnet/scp.h dcmtk-3.7.0/dcmnet/include/dcmtk/dcmnet/scp.h
--- dcmtk-3.7.0.orig/dcmnet/include/dcmtk/dcmnet/scp.h	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmnet/include/dcmtk/dcmnet/scp.h	2026-05-06 10:47:14.145363052 +0200
@@ -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();
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmnet/include/dcmtk/dcmnet/scu.h dcmtk-3.7.0/dcmnet/include/dcmtk/dcmnet/scu.h
--- dcmtk-3.7.0.orig/dcmnet/include/dcmtk/dcmnet/scu.h	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmnet/include/dcmtk/dcmnet/scu.h	2026-05-06 10:47:14.145363052 +0200
@@ -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;
 
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmnet/libsrc/dimse.cc dcmtk-3.7.0/dcmnet/libsrc/dimse.cc
--- dcmtk-3.7.0.orig/dcmnet/libsrc/dimse.cc	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmnet/libsrc/dimse.cc	2026-05-06 10:47:14.145363052 +0200
@@ -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 */
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmnet/libsrc/scp.cc dcmtk-3.7.0/dcmnet/libsrc/scp.cc
--- dcmtk-3.7.0.orig/dcmnet/libsrc/scp.cc	2025-12-15 08:28:13.000000000 +0100
+++ dcmtk-3.7.0/dcmnet/libsrc/scp.cc	2026-05-06 10:47:14.145363052 +0200
@@ -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
 {
diff -urEb '--exclude=.git' dcmtk-3.7.0.orig/dcmnet/libsrc/scu.cc dcmtk-3.7.0/dcmnet/libsrc/scu.cc
--- dcmtk-3.7.0.orig/dcmnet/libsrc/scu.cc	2026-05-06 11:24:55.427982600 +0200
+++ dcmtk-3.7.0/dcmnet/libsrc/scu.cc	2026-05-06 10:47:14.145363052 +0200
@@ -61,6 +61,7 @@
     , m_verbosePCMode(OFFalse)
     , m_datasetConversionMode(OFFalse)
     , m_progressNotificationMode(OFTrue)
+    , m_maxNestingDepth(0)
     , m_secureConnectionEnabled(OFFalse)
     , m_protocolVersion(ASC_AF_Default)
 {
@@ -2505,6 +2506,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)
@@ -2524,6 +2538,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));
@@ -2612,6 +2634,11 @@
     m_progressNotificationMode = mode;
 }
 
+void DcmSCU::setMaxNestingDepth(const Sint32 maxDepth)
+{
+    m_maxNestingDepth = maxDepth;
+}
+
 void DcmSCU::setProtocolVersion(T_ASC_ProtocolFamily protocolVersion)
 {
     m_protocolVersion = protocolVersion;
@@ -2699,6 +2726,11 @@
     return m_progressNotificationMode;
 }
 
+Sint32 DcmSCU::getMaxNestingDepth() const
+{
+    return m_maxNestingDepth;
+}
+
 OFCondition DcmSCU::getDatasetInfo(DcmDataset* dataset,
                                    OFString& sopClassUID,
                                    OFString& sopInstanceUID,