Commit eb5048cd for libheif

commit eb5048cdc5254115c1f17e93b63a304d9e00728f
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Mon May 18 17:31:07 2026 +0200

    validate uncC pixel_size against new security limit and overflow

diff --git a/libheif/api/libheif/heif_security.h b/libheif/api/libheif/heif_security.h
index 76ca958b..39f6a03f 100644
--- a/libheif/api/libheif/heif_security.h
+++ b/libheif/api/libheif/heif_security.h
@@ -74,6 +74,11 @@ typedef struct heif_security_limits

   uint32_t max_bad_pixels;

+  // Upper bound (in bytes) on the pixel_size field of an uncompressed (ISO 23001-17)
+  // uncC box. Caps the byte stride between adjacent pixels and prevents pathological
+  // padding values from blowing up tile-size arithmetic.
+  uint32_t max_iso23001_17_pixel_size_bytes;
+
   // Internal: when libheif derives a limits struct from another one (e.g. to
   // tighten the maximum image size for a specific decode), this points back to
   // the registered context whose total-memory budget the allocation should be
diff --git a/libheif/codecs/uncompressed/unc_boxes.cc b/libheif/codecs/uncompressed/unc_boxes.cc
index 7b69f089..0b235369 100644
--- a/libheif/codecs/uncompressed/unc_boxes.cc
+++ b/libheif/codecs/uncompressed/unc_boxes.cc
@@ -315,6 +315,17 @@ Error Box_uncC::parse(BitstreamRange& range, const heif_security_limits* limits)

     m_pixel_size = range.read32();

+    if (limits->version >= 4 &&
+        limits->max_iso23001_17_pixel_size_bytes != 0 &&
+        m_pixel_size > limits->max_iso23001_17_pixel_size_bytes) {
+      std::stringstream sstr;
+      sstr << "uncC pixel_size (" << m_pixel_size << " bytes) exceeds security limit of "
+           << limits->max_iso23001_17_pixel_size_bytes << " bytes";
+      return {heif_error_Memory_allocation_error,
+              heif_suberror_Security_limit_exceeded,
+              sstr.str()};
+    }
+
     m_row_align_size = range.read32();

     m_tile_align_size = range.read32();
diff --git a/libheif/codecs/uncompressed/unc_decoder.cc b/libheif/codecs/uncompressed/unc_decoder.cc
index 41f66668..92153dd1 100644
--- a/libheif/codecs/uncompressed/unc_decoder.cc
+++ b/libheif/codecs/uncompressed/unc_decoder.cc
@@ -68,7 +68,11 @@ Error unc_decoder::fetch_tile_data(const DataExtent& dataExtent,
     return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Internal error: unc_decoder tile dimensions are 0"};
   }

-  auto sizes = get_tile_data_sizes();
+  auto sizesResult = get_tile_data_sizes();
+  if (sizesResult.is_error()) {
+    return sizesResult.error();
+  }
+  const auto& sizes = *sizesResult;
   uint32_t tileIdx = tile_x + tile_y * (m_width / m_tile_width);

   if (sizes.size() == 1) {
diff --git a/libheif/codecs/uncompressed/unc_decoder.h b/libheif/codecs/uncompressed/unc_decoder.h
index 75d19efe..dc566ab0 100644
--- a/libheif/codecs/uncompressed/unc_decoder.h
+++ b/libheif/codecs/uncompressed/unc_decoder.h
@@ -65,7 +65,7 @@ protected:
               const std::shared_ptr<const Box_uncC>& uncC,
               const std::vector<uint32_t>& uncC_index_to_comp_ids);

-  virtual std::vector<uint64_t> get_tile_data_sizes() const = 0;
+  virtual Result<std::vector<uint64_t>> get_tile_data_sizes() const = 0;

   const Error get_compressed_image_data_uncompressed(const DataExtent& dataExtent,
                                                      const UncompressedImageCodec::unci_properties& properties,
diff --git a/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.cc
index 96e51e82..fd2f7f72 100644
--- a/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.cc
@@ -40,11 +40,16 @@ unc_decoder_block_component_interleave::unc_decoder_block_component_interleave(
 }


-std::vector<uint64_t> unc_decoder_block_component_interleave::get_tile_data_sizes() const
+Result<std::vector<uint64_t>> unc_decoder_block_component_interleave::get_tile_data_sizes() const
 {
   const uint32_t block_size = m_uncC->get_block_size();
   assert(block_size > 0);

+  if (m_tile_width > UINT32_MAX / block_size) {
+    return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                 "uncompressed tile row size exceeds 32-bit range"};
+  }
+
   uint64_t total_tile_size = 0;

   for (const auto& component : m_uncC->get_components()) {
@@ -58,7 +63,7 @@ std::vector<uint64_t> unc_decoder_block_component_interleave::get_tile_data_size
     skip_to_alignment(total_tile_size, m_uncC->get_tile_align_size());
   }

-  return {total_tile_size};
+  return std::vector<uint64_t>{total_tile_size};
 }


diff --git a/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.h
index a040413d..0ced4fca 100644
--- a/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.h
@@ -34,7 +34,7 @@ public:
                                           std::shared_ptr<const Box_uncC> uncC,
                                           const std::vector<uint32_t>& uncC_index_to_comp_ids);

-  std::vector<uint64_t> get_tile_data_sizes() const override;
+  Result<std::vector<uint64_t>> get_tile_data_sizes() const override;

   Error decode_tile(const std::vector<uint8_t>& tile_data,
                     std::shared_ptr<HeifPixelImage>& img,
diff --git a/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.cc
index 075c6a58..64d08026 100644
--- a/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.cc
@@ -40,11 +40,15 @@ unc_decoder_block_pixel_interleave::unc_decoder_block_pixel_interleave(
 }


-std::vector<uint64_t> unc_decoder_block_pixel_interleave::get_tile_data_sizes() const
+Result<std::vector<uint64_t>> unc_decoder_block_pixel_interleave::get_tile_data_sizes() const
 {
   uint32_t pixel_size = m_uncC->get_pixel_size();
   assert(pixel_size > 0);

+  if (m_tile_width > UINT32_MAX / pixel_size) {
+    return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                 "uncompressed tile row size exceeds 32-bit range"};
+  }
   uint32_t bytes_per_row = m_tile_width * pixel_size;
   skip_to_alignment(bytes_per_row, m_uncC->get_row_align_size());

@@ -53,7 +57,7 @@ std::vector<uint64_t> unc_decoder_block_pixel_interleave::get_tile_data_sizes()
     skip_to_alignment(tile_size, m_uncC->get_tile_align_size());
   }

-  return {tile_size};
+  return std::vector<uint64_t>{tile_size};
 }


diff --git a/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.h b/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.h
index 122160db..dd1ab29f 100644
--- a/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.h
@@ -34,7 +34,7 @@ public:
                                      std::shared_ptr<const Box_uncC> uncC,
                                      const std::vector<uint32_t>& uncC_index_to_comp_ids);

-  std::vector<uint64_t> get_tile_data_sizes() const override;
+  Result<std::vector<uint64_t>> get_tile_data_sizes() const override;

   Error decode_tile(const std::vector<uint8_t>& tile_data,
                     std::shared_ptr<HeifPixelImage>& img,
diff --git a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
index 098142fb..7c557703 100644
--- a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
@@ -40,7 +40,7 @@ unc_decoder_bytealign_component_interleave::unc_decoder_bytealign_component_inte
 }


-std::vector<uint64_t> unc_decoder_bytealign_component_interleave::get_tile_data_sizes() const
+Result<std::vector<uint64_t>> unc_decoder_bytealign_component_interleave::get_tile_data_sizes() const
 {
   uint64_t total_tile_size = 0;

@@ -50,6 +50,10 @@ std::vector<uint64_t> unc_decoder_bytealign_component_interleave::get_tile_data_
       skip_to_alignment(bytes_per_sample, component.component_align_size);
     }

+    if (bytes_per_sample != 0 && m_tile_width > UINT32_MAX / bytes_per_sample) {
+      return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                   "uncompressed tile row size exceeds 32-bit range"};
+    }
     uint32_t bytes_per_row = bytes_per_sample * m_tile_width;
     skip_to_alignment(bytes_per_row, m_uncC->get_row_align_size());

@@ -60,7 +64,7 @@ std::vector<uint64_t> unc_decoder_bytealign_component_interleave::get_tile_data_
     skip_to_alignment(total_tile_size, m_uncC->get_tile_align_size());
   }

-  return {total_tile_size};
+  return std::vector<uint64_t>{total_tile_size};
 }


diff --git a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.h
index c52b9f2b..1bd8db13 100644
--- a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.h
@@ -34,7 +34,7 @@ public:
                                               std::shared_ptr<const Box_uncC> uncC,
                                               const std::vector<uint32_t>& uncC_index_to_comp_ids);

-  std::vector<uint64_t> get_tile_data_sizes() const override;
+  Result<std::vector<uint64_t>> get_tile_data_sizes() const override;

   Error decode_tile(const std::vector<uint8_t>& tile_data,
                     std::shared_ptr<HeifPixelImage>& img,
diff --git a/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
index 8e5c1da4..db422dfe 100644
--- a/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
@@ -25,7 +25,7 @@
 #include <vector>


-std::vector<uint64_t> unc_decoder_component_interleave::get_tile_data_sizes() const
+Result<std::vector<uint64_t>> unc_decoder_component_interleave::get_tile_data_sizes() const
 {
   if (m_uncC->get_interleave_type() == interleave_mode_tile_component) {
     // Per-component sizes for scattered reads
@@ -43,9 +43,17 @@ std::vector<uint64_t> unc_decoder_component_interleave::get_tile_data_sizes() co
       if (m_uncC->get_pixel_size() != 0) {
         uint32_t bytes_per_pixel = (bits_per_pixel + 7) / 8;
         skip_to_alignment(bytes_per_pixel, m_uncC->get_pixel_size());
+        if (bytes_per_pixel != 0 && m_tile_width > UINT32_MAX / bytes_per_pixel) {
+          return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                       "uncompressed tile row size exceeds 32-bit range"};
+        }
         bytes_per_row = bytes_per_pixel * m_tile_width;
       }
       else {
+        if (bits_per_pixel != 0 && m_tile_width > UINT32_MAX / bits_per_pixel) {
+          return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                       "uncompressed tile row size exceeds 32-bit range"};
+        }
         bytes_per_row = (bits_per_pixel * m_tile_width + 7) / 8;
       }

@@ -74,6 +82,10 @@ std::vector<uint64_t> unc_decoder_component_interleave::get_tile_data_sizes() co
       bits_per_component = bytes_per_component * 8;
     }

+    if (bits_per_component != 0 && entry.tile_width > UINT32_MAX / bits_per_component) {
+      return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                   "uncompressed tile row size exceeds 32-bit range"};
+    }
     uint32_t bytes_per_tile_row = (bits_per_component * entry.tile_width + 7) / 8;
     skip_to_alignment(bytes_per_tile_row, m_uncC->get_row_align_size());
     uint64_t bytes_per_tile = uint64_t{bytes_per_tile_row} * entry.tile_height;
@@ -84,7 +96,7 @@ std::vector<uint64_t> unc_decoder_component_interleave::get_tile_data_sizes() co
     skip_to_alignment(total_tile_size, m_uncC->get_tile_align_size());
   }

-  return {total_tile_size};
+  return std::vector<uint64_t>{total_tile_size};
 }


diff --git a/libheif/codecs/uncompressed/unc_decoder_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
index 731e261c..cb5a1702 100644
--- a/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
@@ -36,7 +36,7 @@ public:
                                     const std::vector<uint32_t>& uncC_index_to_comp_ids) :
       unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC), uncC_index_to_comp_ids) {}

-  std::vector<uint64_t> get_tile_data_sizes() const override;
+  Result<std::vector<uint64_t>> get_tile_data_sizes() const override;

   Error decode_tile(const std::vector<uint8_t>& tile_data,
                     std::shared_ptr<HeifPixelImage>& img,
diff --git a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
index 81223107..73526f5c 100644
--- a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
@@ -26,37 +26,34 @@
 #include <vector>


-std::vector<uint64_t> unc_decoder_mixed_interleave::get_tile_data_sizes() const
+Result<std::vector<uint64_t>> unc_decoder_mixed_interleave::get_tile_data_sizes() const
 {
   uint64_t tile_size = 0;

   for (const ChannelListEntry& entry : channelList) {
-    if (entry.channel == heif_channel_Cb || entry.channel == heif_channel_Cr) {
-      uint32_t bits_per_row = entry.bits_per_component_sample * entry.tile_width;
-      bits_per_row = (bits_per_row + 7) & ~7U; // align to byte boundary
-
-      tile_size += uint64_t{bits_per_row} / 8 * entry.tile_height;
+    uint32_t bits_per_component = entry.bits_per_component_sample;
+    if (entry.channel != heif_channel_Cb && entry.channel != heif_channel_Cr
+        && entry.component_alignment > 0) {
+      uint32_t bytes_per_component = (bits_per_component + 7) / 8;
+      skip_to_alignment(bytes_per_component, entry.component_alignment);
+      bits_per_component = bytes_per_component * 8;
     }
-    else {
-      uint32_t bits_per_component = entry.bits_per_component_sample;
-      if (entry.component_alignment > 0) {
-        uint32_t bytes_per_component = (bits_per_component + 7) / 8;
-        skip_to_alignment(bytes_per_component, entry.component_alignment);
-        bits_per_component = bytes_per_component * 8;
-      }

-      uint32_t bits_per_row = bits_per_component * entry.tile_width;
-      bits_per_row = (bits_per_row + 7) & ~7U; // align to byte boundary
-
-      tile_size += uint64_t{bits_per_row} / 8 * entry.tile_height;
+    if (bits_per_component != 0 && entry.tile_width > UINT32_MAX / bits_per_component) {
+      return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                   "uncompressed tile row size exceeds 32-bit range"};
     }
+    uint32_t bits_per_row = bits_per_component * entry.tile_width;
+    bits_per_row = (bits_per_row + 7) & ~7U; // align to byte boundary
+
+    tile_size += uint64_t{bits_per_row} / 8 * entry.tile_height;
   }

   if (m_uncC->get_tile_align_size() != 0) {
     skip_to_alignment(tile_size, m_uncC->get_tile_align_size());
   }

-  return {tile_size};
+  return std::vector<uint64_t>{tile_size};
 }


diff --git a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
index 4e441401..f7eb56b3 100644
--- a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
@@ -33,7 +33,7 @@ public:
   unc_decoder_mixed_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC, const std::vector<uint32_t>& uncC_index_to_comp_ids) :
       unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC), uncC_index_to_comp_ids) {}

-  std::vector<uint64_t> get_tile_data_sizes() const override;
+  Result<std::vector<uint64_t>> get_tile_data_sizes() const override;

   Error decode_tile(const std::vector<uint8_t>& tile_data,
                     std::shared_ptr<HeifPixelImage>& img,
diff --git a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
index de7169d6..8093502b 100644
--- a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
@@ -25,7 +25,7 @@
 #include <vector>


-std::vector<uint64_t> unc_decoder_pixel_interleave::get_tile_data_sizes() const
+Result<std::vector<uint64_t>> unc_decoder_pixel_interleave::get_tile_data_sizes() const
 {
   uint32_t bits_per_row = 0;
   for (uint32_t x = 0; x < m_tile_width; x++) {
@@ -51,6 +51,10 @@ std::vector<uint64_t> unc_decoder_pixel_interleave::get_tile_data_sizes() const
       bits_per_pixel = bytes_per_pixel * 8;
     }

+    if (bits_per_pixel > UINT32_MAX - bits_per_row) {
+      return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                   "uncompressed tile row size exceeds 32-bit range"};
+    }
     bits_per_row += bits_per_pixel;
   }

@@ -62,7 +66,7 @@ std::vector<uint64_t> unc_decoder_pixel_interleave::get_tile_data_sizes() const
     skip_to_alignment(total_tile_size, m_uncC->get_tile_align_size());
   }

-  return {total_tile_size};
+  return std::vector<uint64_t>{total_tile_size};
 }


diff --git a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
index 45aa55ae..833096cb 100644
--- a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
@@ -33,7 +33,7 @@ public:
   unc_decoder_pixel_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC, const std::vector<uint32_t>& uncC_index_to_comp_ids) :
       unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC), uncC_index_to_comp_ids) {}

-  std::vector<uint64_t> get_tile_data_sizes() const override;
+  Result<std::vector<uint64_t>> get_tile_data_sizes() const override;

   Error decode_tile(const std::vector<uint8_t>& tile_data,
                     std::shared_ptr<HeifPixelImage>& img,
diff --git a/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
index e8dc47c9..a4ece8a2 100644
--- a/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
@@ -25,7 +25,7 @@
 #include <vector>


-std::vector<uint64_t> unc_decoder_row_interleave::get_tile_data_sizes() const
+Result<std::vector<uint64_t>> unc_decoder_row_interleave::get_tile_data_sizes() const
 {
   uint32_t bits_per_row = 0;
   for (const ChannelListEntry& entry : channelList) {
@@ -39,14 +39,25 @@ std::vector<uint64_t> unc_decoder_row_interleave::get_tile_data_sizes() const
       bits_per_component = bytes_per_component * 8;
     }

+    uint32_t row_bits;
+    if (bits_per_component != 0 && m_tile_width > UINT32_MAX / bits_per_component) {
+      return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                   "uncompressed tile row size exceeds 32-bit range"};
+    }
     if (m_uncC->get_row_align_size() != 0) {
       uint32_t bytes_this_row = (bits_per_component * m_tile_width + 7) / 8;
       skip_to_alignment(bytes_this_row, m_uncC->get_row_align_size());
-      bits_per_row += bytes_this_row * 8;
+      row_bits = bytes_this_row * 8;
     }
     else {
-      bits_per_row += bits_per_component * m_tile_width;
+      row_bits = bits_per_component * m_tile_width;
+    }
+
+    if (row_bits > UINT32_MAX - bits_per_row) {
+      return Error{heif_error_Invalid_input, heif_suberror_Invalid_image_size,
+                   "uncompressed tile row size exceeds 32-bit range"};
     }
+    bits_per_row += row_bits;

     bits_per_row = (bits_per_row + 7) & ~7U;
   }
@@ -62,7 +73,7 @@ std::vector<uint64_t> unc_decoder_row_interleave::get_tile_data_sizes() const
     skip_to_alignment(total_tile_size, m_uncC->get_tile_align_size());
   }

-  return {total_tile_size};
+  return std::vector<uint64_t>{total_tile_size};
 }


diff --git a/libheif/codecs/uncompressed/unc_decoder_row_interleave.h b/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
index 6c028e83..fe85d4d7 100644
--- a/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
@@ -35,7 +35,7 @@ public:
       unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC), uncC_index_to_comp_ids) {}


-  std::vector<uint64_t> get_tile_data_sizes() const override;
+  Result<std::vector<uint64_t>> get_tile_data_sizes() const override;

   Error decode_tile(const std::vector<uint8_t>& tile_data,
                     std::shared_ptr<HeifPixelImage>& img,
diff --git a/libheif/context.cc b/libheif/context.cc
index ceb43f14..37c9e30a 100644
--- a/libheif/context.cc
+++ b/libheif/context.cc
@@ -201,6 +201,7 @@ static void copy_security_limits(heif_security_limits* dst, const heif_security_

   if (src->version >= 4) {
     dst->max_bad_pixels = src->max_bad_pixels;
+    dst->max_iso23001_17_pixel_size_bytes = src->max_iso23001_17_pixel_size_bytes;
   }

   // `parent` is an internal field; user-supplied limits are always treated as
diff --git a/libheif/security_limits.cc b/libheif/security_limits.cc
index d6d9a7dc..2eac6a39 100644
--- a/libheif/security_limits.cc
+++ b/libheif/security_limits.cc
@@ -59,6 +59,9 @@ heif_security_limits global_security_limits{
     // --- version 4

     .max_bad_pixels = 1000,
+
+    .max_iso23001_17_pixel_size_bytes = 256,
+
     .parent = nullptr
 };