Commit 720cad26 for libheif

commit 720cad262288196225c5c9c9cc7ee530309f020f
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Sat Nov 29 21:58:16 2025 +0100

    heif_list_compatible_brands() checks that input starts with 'ftyp' box. (fixes #1633)

diff --git a/libheif/api/libheif/heif_brands.cc b/libheif/api/libheif/heif_brands.cc
index 43938d68..c030785c 100644
--- a/libheif/api/libheif/heif_brands.cc
+++ b/libheif/api/libheif/heif_brands.cc
@@ -108,11 +108,35 @@ heif_error heif_list_compatible_brands(const uint8_t* data, int len, heif_brand2
     return {heif_error_Usage_error, heif_suberror_Invalid_parameter_value, "data length must be positive"};
   }

+  const heif_security_limits* security_limits = heif_get_global_security_limits();
+
+
+  // --- check that file begins with ftyp box
+
+  {
+    auto stream = std::make_shared<StreamReader_memory>(data, len, false);
+    BitstreamRange range(stream, len);
+
+    BoxHeader hdr;
+    Error err = hdr.parse_header(range);
+    if (err) {
+      return {err.error_code, err.sub_error_code, "error reading ftype box header"};
+    }
+
+    if (hdr.get_short_type() != fourcc("ftyp")) {
+      return {
+        heif_error_Invalid_input,
+        heif_suberror_Unspecified,
+        "File does not begin with 'ftyp' box."
+      };
+    }
+  }
+
   auto stream = std::make_shared<StreamReader_memory>(data, len, false);
   BitstreamRange range(stream, len);

   std::shared_ptr<Box> box;
-  Error err = Box::read(range, &box, heif_get_global_security_limits());
+  Error err = Box::read(range, &box, security_limits);
   if (err) {
     if (err.sub_error_code == heif_suberror_End_of_data) {
       return {err.error_code, err.sub_error_code, "insufficient input data"};
@@ -128,6 +152,15 @@ heif_error heif_list_compatible_brands(const uint8_t* data, int len, heif_brand2

   auto brands = ftyp->list_brands();
   size_t nBrands = brands.size();
+
+  if (nBrands > security_limits->max_number_of_file_brands) {
+    return {
+      heif_error_Memory_allocation_error,
+      heif_suberror_Security_limit_exceeded,
+      "File contains more brands than allowed by security limits."
+    };
+  }
+
   *out_brands = (heif_brand2*) malloc(sizeof(heif_brand2) * nBrands);
   *out_size = (int)nBrands;

diff --git a/libheif/box.cc b/libheif/box.cc
index a474488c..d47952ab 100644
--- a/libheif/box.cc
+++ b/libheif/box.cc
@@ -1254,6 +1254,14 @@ Error Box_ftyp::parse(BitstreamRange& range, const heif_security_limits* limits)

   uint64_t n_minor_brands = (get_box_size() - get_header_size() - 8) / 4;

+  if (n_minor_brands > limits->max_number_of_file_brands) {
+    return {
+      heif_error_Memory_allocation_error,
+      heif_suberror_Security_limit_exceeded,
+      "Number of minor brands in file exceeds security limit"
+    };
+  }
+
   for (uint64_t i = 0; i < n_minor_brands && !range.error(); i++) {
     m_compatible_brands.push_back(range.read32());
   }