Hi,

bookworm's expat (2.5.0-1+deb12u5) is still open for four CVEs that
2.10.0-1 fixed in unstable: CVE-2026-113351 (<postponed>), CVE-2026-115506,
CVE-2026-117610 and CVE-2026-118370. expat isn't in dla-needed.txt, and the
debian/bookworm branch in lts-team/packages/expat is still at deb12u5, so I
prepared backports of three of them on top of deb12u5. The debdiff is
attached; please use as much or as little of it as is useful. I'm not on
the LTS team and can't upload.

CVE-2026-117610 (upstream PR #1444)
The library change applies unchanged. The bug does affect deb12u5: I ran
upstream's test scenario (external entity subparser, an empty non-final
XML_Parse(), then a document containing a PI) as a small standalone program
under ASan+UBSan. On deb12u5, reportProcessingInstruction() reads
enc->minBytesPerChar from uninitialized heap memory (UBSan: "signed integer
overflow: -1094795586 * 2", i.e. ASan's 0xbe fill), deterministically. The
same program SEGVs on upstream R_2_9_0. With the patch it runs clean and
the handler gets target="target", data="data". The upstream regression test
is ported into tests/runtests.c. Note that without sanitizers the ported
test happened to pass on deb12u5 as well, since the uninitialized memory
held usable values.

CVE-2026-113351 (upstream PR #1431)
The CVE text says 2.7.2 and later, but deb12u4 backported the 2.7.2
allocation tracker (CVE-2025-59375), so bookworm is affected, as the
tracker says. I ported the two upstream tests: both fail on deb12u5 (after
XML_ParserReset() the amplification limit set by the application is lost,
and after one large document a small one is refused with
XML_ERROR_NO_MEMORY), and both pass with the patch. The 2.5.0 differences
(XmlBigCount, XML_DTD guard) are noted in the patch header.

CVE-2026-118370 (upstream PR #1450)
Hand-ported, because storeAtts() in 2.5.0 shares one "int i" between
several loops; the loops over attIndex get their own size_t counters. Not
reproduced, since triggering it needs more than 2^31 attributes; the
affected code is the same as upstream before the fix.

Not included:
- CVE-2026-115506 (PR #1433): this adds about 400 lines of new code that
precompute entity expansion sizes, to cut the CPU time of a billion-laughs
style DoS. I don't think it is a reasonable backport for 2.5.0, so I'm
leaving that decision to you.
- CVE-2025-66382: no upstream fix yet.

Side finding: tests/runtests on deb12u5 fails 1 of 365 checks
(test_nsalloc_realloc_attributes). I bisected the series to
CVE-2025-59375-10.patch: the same upstream commit (cfce28e17167) also
changed that test's expectation for XML_GE=1, but the backport didn't carry
the test change over. debian/rules builds the tests but never runs them,
which is presumably why it went unnoticed. The debdiff adds the test change
as CVE-2025-59375-tests.patch.

Testing:
- All 74 patches apply to the orig tarball with no fuzz or offset, and
dpkg-source -b builds the source package.
- Built with upstream's CMake build and -DXML_GE=1 as in debian/rules
(automake isn't available on my build host, so Debian's autotools build was
NOT run; the CMake build needed XML_DTD/XML_NS set to 1 in the generated
expat_config.h, because the earlier backports use "#if XML_DTD == 1").
- runtests and runtestspp: 368/368 with -O2, and 368/368 with
ASan+UBSan+LSan with no sanitizer reports. Unpatched deb12u5 in the same
setup: 364/365.
- The library also compiles with -DXML_UNICODE (libexpatw) and adds no new
compiler warnings.

Regards,
Sumit Verma
diff -urN old/debian/changelog new/debian/changelog
--- old/debian/changelog	2026-10-21 18:34:41.000000000 -0400
+++ new/debian/changelog	2026-11-05 15:20:17.000000000 -0500
@@ -1,3 +1,19 @@
+expat (2.5.0-1+deb12u6) bookworm-security; urgency=medium
+
+  * Non-maintainer upload.
+  * Backport upstream security fixes:
+    - CVE-2026-118370: Protect attIndex and nPrefixes in storeAtts from
+      signed integer overflow.
+    - CVE-2026-117610: Fix initial non-final empty subparser call with a
+      handler.
+    - CVE-2026-113351: Fix XML_ParserReset interaction with allocation
+      tracking and amplification accounting.
+  * Update test_nsalloc_realloc_attributes for the allocation tracking
+    added in 2.5.0-1+deb12u4 (CVE-2025-59375), as upstream did in the
+    same commit; tests/runtests failed 1 of 365 checks.
+
+ -- Sumit Verma <[email protected]>  Thu, 05 Nov 2026 15:20:17 -0500
+
 expat (2.5.0-1+deb12u5) bookworm-security; urgency=medium
 
   * Backport upstream security patches:
diff -urN old/debian/patches/CVE-2025-59375-tests.patch new/debian/patches/CVE-2025-59375-tests.patch
--- old/debian/patches/CVE-2025-59375-tests.patch	1969-12-31 19:00:00.000000000 -0500
+++ new/debian/patches/CVE-2025-59375-tests.patch	2026-11-05 15:13:18.000000000 -0500
@@ -0,0 +1,30 @@
+Description: Update test_nsalloc_realloc_attributes for allocation tracking
+ With the CVE-2025-59375 allocation tracking (XML_GE=1, as set in debian/rules),
+ expat_realloc relies on expat_malloc, so the first parse already succeeds when
+ reallocations fail. Upstream changed the expectation of this test in the same
+ commit; the 2.5.0-1+deb12u4 backport (CVE-2025-59375-10.patch) took the library change but
+ not this test change, so tests/runtests failed 1 of 365 checks. This is the
+ tests/nsalloc_tests.c hunk of the same upstream commit, ported to runtests.c
+ (its other test hunk, in test_buffer_can_grow_to_max, has no 2.5.0 counterpart).
+Origin: backport, https://github.com/libexpat/libexpat/commit/cfce28e171676fe6f70d17b97ed8a59eaeb83f15
+Forwarded: not-needed
+Last-Update: 2026-11-05
+---
+--- a/expat/tests/runtests.c
++++ b/expat/tests/runtests.c
+@@ -11781,10 +11781,15 @@
+     nsalloc_teardown();
+     nsalloc_setup();
+   }
++#if XML_GE == 1
++  assert_true(
++      i == 0); // because expat_realloc relies on expat_malloc to some extent
++#else
+   if (i == 0)
+     fail("Parsing worked despite failing reallocations");
+   else if (i == max_realloc_count)
+     fail("Parsing failed at max reallocation count");
++#endif
+ }
+ END_TEST
+ 
diff -urN old/debian/patches/CVE-2026-113351.patch new/debian/patches/CVE-2026-113351.patch
--- old/debian/patches/CVE-2026-113351.patch	1969-12-31 19:00:00.000000000 -0500
+++ new/debian/patches/CVE-2026-113351.patch	2026-11-05 15:18:31.000000000 -0500
@@ -0,0 +1,214 @@
+Description: Fix XML_ParserReset interaction with allocation tracking and accounting (CVE-2026-113351)
+ Backport of upstream PR #1431 to expat 2.5.0-1+deb12u5, whose CVE-2025-59375
+ backport added the allocation tracker. After XML_ParserReset(), the tracker
+ kept counting memory still held from the previous document while the
+ billion-laughs byte counters restarted from zero, so after one large document
+ every allocation for the next document was refused (XML_ERROR_NO_MEMORY).
+ The tracker now measures relative to the bytes allocated at the last reset,
+ and the reset no longer discards amplification limits set by the application.
+ .
+ 2.5.0 differences: the tracker uses XmlBigCount and the accounting block in
+ parserInit() is guarded by XML_DTD; the two new tests are ported from
+ tests/acc_tests.c and tests/alloc_tests.c into tests/runtests.c, parsing in one
+ XML_Parse() call (upstream skips them for chunked parsing) and registering the
+ alloc tracker test in tc_misc, since tc_alloc installs a failing allocator.
+Origin: backport, https://github.com/libexpat/libexpat/commit/a6cf8a6944b6 https://github.com/libexpat/libexpat/commit/8b722a1453b8 https://github.com/libexpat/libexpat/commit/c400537c2df3 https://github.com/libexpat/libexpat/commit/f74501d61e09
+Bug: https://github.com/libexpat/libexpat/pull/1431
+Bug-Debian: https://bugs.debian.org/1151840
+Last-Update: 2026-11-05
+---
+--- a/expat/lib/xmlparse.c
++++ b/expat/lib/xmlparse.c
+@@ -453,6 +453,7 @@
+ typedef struct MALLOC_TRACKER {
+   XmlBigCount bytesAllocated;
+   XmlBigCount peakBytesAllocated; // updated live only for debug level >=2
++  XmlBigCount bytesAllocatedWhenLastReset;
+   unsigned long debugLevel;
+   float maximumAmplificationFactor; // >=1.0
+   XmlBigCount activationThresholdBytes;
+@@ -605,7 +606,8 @@
+                                const XML_Char *nameSep, DTD *dtd,
+                                XML_Parser parentParser);
+ 
+-static void parserInit(XML_Parser parser, const XML_Char *encodingName);
++static void parserInit(XML_Parser parser, const XML_Char *encodingName,
++                       XML_Bool isReset);
+ 
+ #ifdef XML_DTD
+ static float accountingGetCurrentAmplification(XML_Parser rootParser);
+@@ -803,11 +805,22 @@
+   XmlBigCount newTotal = 0;
+   bool tolerable = true;
+ 
++  // The idea is to subtract the amount of memory that was already
++  // allocated the last time that `XML_ParserReset` was called for
++  // this parser, the memory use of one document could skew the
++  // memory stats of the next document.
++  const XmlBigCount bytesAllocated
++      = (rootParser->m_alloc_tracker.bytesAllocatedWhenLastReset
++         > rootParser->m_alloc_tracker.bytesAllocated)
++            ? 0
++            : (rootParser->m_alloc_tracker.bytesAllocated
++               - rootParser->m_alloc_tracker.bytesAllocatedWhenLastReset);
++
+   // Detect integer overflow
+-  if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated < increase) {
++  if ((XmlBigCount)-1 - bytesAllocated < increase) {
+     tolerable = false;
+   } else {
+-    newTotal = rootParser->m_alloc_tracker.bytesAllocated + increase;
++    newTotal = bytesAllocated + increase;
+ 
+     if (newTotal >= rootParser->m_alloc_tracker.activationThresholdBytes) {
+       assert(newTotal > 0);
+@@ -1513,7 +1526,7 @@
+ 
+   poolInit(&parser->m_tempPool, parser);
+   poolInit(&parser->m_temp2Pool, parser);
+-  parserInit(parser, encodingName);
++  parserInit(parser, encodingName, /*isReset=*/XML_FALSE);
+ 
+   if (encodingName && ! parser->m_protocolEncodingName) {
+     if (dtd) {
+@@ -1540,7 +1553,7 @@
+ }
+ 
+ static void
+-parserInit(XML_Parser parser, const XML_Char *encodingName) {
++parserInit(XML_Parser parser, const XML_Char *encodingName, XML_Bool isReset) {
+   parser->m_processor = prologInitProcessor;
+   XmlPrologStateInit(&parser->m_prologState);
+   if (encodingName != NULL) {
+@@ -1619,15 +1632,24 @@
+   parser->m_hash_secret_salt = 0;
+ 
+ #ifdef XML_DTD
+-  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
+-  parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
+-  parser->m_accounting.maximumAmplificationFactor
+-      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
+-  parser->m_accounting.activationThresholdBytes
+-      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
+-
+-  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
+-  parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
++  parser->m_accounting.countBytesDirect = 0;
++  parser->m_accounting.countBytesIndirect = 0;
++  if (! isReset) {
++    parser->m_accounting.debugLevel
++        = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
++    parser->m_accounting.maximumAmplificationFactor
++        = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
++    parser->m_accounting.activationThresholdBytes
++        = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
++  }
++
++  parser->m_entity_stats.countEverOpened = 0;
++  parser->m_entity_stats.currentDepth = 0;
++  parser->m_entity_stats.maximumDepthSeen = 0;
++  if (! isReset)
++    parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
++#else
++  UNUSED_P(isReset);
+ #endif
+ }
+ 
+@@ -1696,8 +1718,14 @@
+   poolClear(&parser->m_temp2Pool);
+   FREE(parser, (void *)parser->m_protocolEncodingName);
+   parser->m_protocolEncodingName = NULL;
+-  parserInit(parser, encodingName);
++  parserInit(parser, encodingName, /*isReset=*/XML_TRUE);
+   dtdReset(parser->m_dtd, parser);
++
++#if XML_GE == 1
++  parser->m_alloc_tracker.bytesAllocatedWhenLastReset
++      = parser->m_alloc_tracker.bytesAllocated;
++#endif
++
+   return XML_TRUE;
+ }
+ 
+--- a/expat/tests/runtests.c
++++ b/expat/tests/runtests.c
+@@ -13223,8 +13223,68 @@
+     fail("unsignedCharToPrintable result mistaken");
+ }
+ END_TEST
++
++START_TEST(test_amplification_reset_neutrality) {
++  const char *const doc
++      = "<!DOCTYPE r [<!ENTITY e 'general entity'>]><r>&e;</r>";
++  XML_Parser parser = XML_ParserCreate(NULL);
++  assert_true(
++      XML_SetBillionLaughsAttackProtectionMaximumAmplification(parser, 1.0f)
++      == XML_TRUE);
++  assert_true(XML_SetBillionLaughsAttackProtectionActivationThreshold(parser, 0)
++              == XML_TRUE);
++
++  assert_true(XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_TRUE)
++              == XML_STATUS_ERROR);
++  assert_true(XML_GetErrorCode(parser) == XML_ERROR_AMPLIFICATION_LIMIT_BREACH);
++
++  assert_true(XML_ParserReset(parser, NULL) == XML_TRUE);
++
++  assert_true(XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_TRUE)
++              == XML_STATUS_ERROR);
++  assert_true(XML_GetErrorCode(parser) == XML_ERROR_AMPLIFICATION_LIMIT_BREACH);
++
++  XML_ParserFree(parser);
++}
++END_TEST
+ #endif // defined(XML_DTD)
+ 
++#if XML_GE == 1
++START_TEST(test_alloc_tracker_reset_neutrality) {
++  XML_Parser parser = XML_ParserCreate(NULL);
++  assert_true(parser != NULL);
++
++  const char *const small = "<hello/>";
++
++  // Create a document that drives `parser->m_alloc_tracker.bytesAllocated`
++  // towards the activation threshold
++  const size_t bigSizeBytes
++      = (size_t)(1.1f * EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT);
++  const char *const before = "<doc a='";
++  const char *const after = "'/>";
++  char *const big = (char *)malloc(bigSizeBytes);
++  assert_true(big != NULL);
++  memset(big, 'X', bigSizeBytes);
++  memcpy(big, before, strlen(before)); // without zero terminator
++  strcpy(big + (bigSizeBytes - strlen(after) - 1),
++         after);                                // with zero terminator
++  assert_true(strlen(big) == bigSizeBytes - 1); // self-test
++
++  assert_true(XML_Parse(parser, big, (int)strlen(big), /*isFinal=*/XML_TRUE)
++              == XML_STATUS_OK);
++
++  free(big);
++
++  assert_true(XML_ParserReset(parser, NULL) == XML_TRUE);
++
++  assert_true(XML_Parse(parser, small, (int)strlen(small), /*isFinal=*/XML_TRUE)
++              == XML_STATUS_OK);
++
++  XML_ParserFree(parser);
++}
++END_TEST
++#endif // XML_GE == 1
++
+ static Suite *
+ make_suite(void) {
+   Suite *s = suite_create("basic");
+@@ -13637,6 +13697,10 @@
+   tcase_add_test(tc_accounting, test_accounting_precision);
+   tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
+   tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
++  tcase_add_test(tc_accounting, test_amplification_reset_neutrality);
++#endif
++#if XML_GE == 1
++  tcase_add_test(tc_misc, test_alloc_tracker_reset_neutrality);
+ #endif
+ 
+   return s;
diff -urN old/debian/patches/CVE-2026-117610.patch new/debian/patches/CVE-2026-117610.patch
--- old/debian/patches/CVE-2026-117610.patch	1969-12-31 19:00:00.000000000 -0500
+++ new/debian/patches/CVE-2026-117610.patch	2026-11-05 15:04:23.000000000 -0500
@@ -0,0 +1,97 @@
+Description: Fix initial non-final empty subparser call with a handler (CVE-2026-117610)
+ Backport of upstream PR #1444 to expat 2.5.0. An external entity parser that
+ is first fed an empty, non-final buffer reached externalEntityInitProcessor3
+ with XML_TOK_NONE; externalEntityInitProcessor2 now returns early and waits
+ for more input. The library change applies unchanged; the regression test is
+ ported from tests/misc_tests.c to the single tests/runtests.c used by 2.5.0
+ (XCS()/xcstrcmp() instead of xcsdup_str()/xcscmp()).
+Origin: backport, https://github.com/libexpat/libexpat/commit/bfc28346fa3e https://github.com/libexpat/libexpat/commit/cedb704d2cad
+Bug: https://github.com/libexpat/libexpat/pull/1444
+Bug-Debian: https://bugs.debian.org/1152343
+Last-Update: 2026-11-05
+---
+--- a/expat/lib/xmlparse.c
++++ b/expat/lib/xmlparse.c
+@@ -3271,6 +3271,11 @@
+     }
+     parser->m_eventPtr = start;
+     return XML_ERROR_PARTIAL_CHAR;
++  case XML_TOK_NONE:
++    if (! parser->m_parsingStatus.finalBuffer) {
++      *endPtr = start;
++    }
++    return XML_ERROR_NONE;
+   }
+   parser->m_processor = externalEntityInitProcessor3;
+   return externalEntityInitProcessor3(parser, start, end, endPtr);
+--- a/expat/tests/runtests.c
++++ b/expat/tests/runtests.c
+@@ -9038,6 +9038,60 @@
+ }
+ END_TEST
+ 
++static void XMLCALL
++comparingPiHandler(void *userData, const XML_Char *target,
++                   const XML_Char *data) {
++  UNUSED_P(userData);
++  assert_true(target != NULL);
++  assert_true(data != NULL);
++  assert_true(xcstrcmp(target, XCS("target")) == 0);
++  assert_true(xcstrcmp(data, XCS("data")) == 0);
++}
++
++static int XMLCALL
++piParsingExternalEntityHandler(XML_Parser parent, const XML_Char *context,
++                               const XML_Char *base, const XML_Char *systemId,
++                               const XML_Char *publicId) {
++  UNUSED_P(base);
++  UNUSED_P(systemId);
++  UNUSED_P(publicId);
++
++  const char *const doc = "<?target data?>";
++
++  XML_Parser subParser = XML_ExternalEntityParserCreate(parent, context, NULL);
++  assert_true(subParser != NULL);
++
++  assert_true(_XML_Parse_SINGLE_BYTES(subParser, "", 0, /*isFinal=*/XML_FALSE)
++              == XML_STATUS_OK);
++  assert_true(_XML_Parse_SINGLE_BYTES(subParser, doc, (int)strlen(doc),
++                                      /*isFinal=*/XML_TRUE)
++              == XML_STATUS_OK);
++
++  XML_ParserFree(subParser);
++
++  return XML_STATUS_OK;
++}
++
++START_TEST(test_misc_empty_nonfinal_subparser_parse) {
++  const char *const doc = "<!DOCTYPE root [\n"
++                          "  <!ENTITY ext SYSTEM 'external.dtd'>\n"
++                          "]>\n"
++                          "<root>&ext;</root>\n";
++
++  XML_Parser parser = XML_ParserCreate(NULL);
++  assert_true(parser != NULL);
++
++  XML_SetProcessingInstructionHandler(parser, comparingPiHandler);
++  XML_SetExternalEntityRefHandler(parser, piParsingExternalEntityHandler);
++
++  assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
++                                      /*isFinal=*/XML_TRUE)
++              == XML_STATUS_OK);
++
++  XML_ParserFree(parser);
++}
++END_TEST
++
+ static void
+ alloc_setup(void) {
+   XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
+@@ -13481,6 +13535,7 @@
+   tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser);
+   tcase_add_test__ifdef_xml_dtd(tc_misc, test_renter_loop_finite_content);
+   tcase_add_test(tc_misc, test_misc_expected_event_ptr_issue_980);
++  tcase_add_test(tc_misc, test_misc_empty_nonfinal_subparser_parse);
+ 
+   suite_add_tcase(s, tc_alloc);
+   tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown);
diff -urN old/debian/patches/CVE-2026-118370.patch new/debian/patches/CVE-2026-118370.patch
--- old/debian/patches/CVE-2026-118370.patch	1969-12-31 19:00:00.000000000 -0500
+++ new/debian/patches/CVE-2026-118370.patch	2026-11-05 15:03:39.000000000 -0500
@@ -0,0 +1,99 @@
+Description: Protect attIndex and nPrefixes in storeAtts from signed integer overflow (CVE-2026-118370)
+ Backport of upstream PR #1450 to expat 2.5.0. Upstream changes attIndex,
+ nPrefixes and the matching loop counters in storeAtts() to size_t and rejects
+ counts above INT_MAX before storing them in the int-typed
+ m_nSpecifiedAtts / m_idAttIndex fields. In 2.5.0 the function shares one
+ "int i" between several loops, so the loops over attIndex use their own
+ size_t counters (k, ai) instead.
+Origin: backport, https://github.com/libexpat/libexpat/commit/621cb2c78b25 https://github.com/libexpat/libexpat/commit/1bac53c4fc46
+Bug: https://github.com/libexpat/libexpat/pull/1450
+Bug-Debian: https://bugs.debian.org/1152337
+Last-Update: 2026-11-05
+---
+--- a/expat/lib/xmlparse.c
++++ b/expat/lib/xmlparse.c
+@@ -3908,12 +3908,12 @@
+   ELEMENT_TYPE *elementType;
+   int nDefaultAtts;
+   const XML_Char **appAtts; /* the attribute list for the application */
+-  int attIndex = 0;
++  size_t attIndex = 0;
+   int prefixLen;
+   int i;
+   int n;
+   XML_Char *uri;
+-  int nPrefixes = 0;
++  size_t nPrefixes = 0;
+   BINDING *binding;
+   const XML_Char *localPart;
+ 
+@@ -4095,11 +4095,16 @@
+   }
+ 
+   /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
+-  parser->m_nSpecifiedAtts = attIndex;
++  // Detect and reject integer overflow
++  if (attIndex > INT_MAX)
++    return XML_ERROR_NO_MEMORY;
++  parser->m_nSpecifiedAtts = (int)attIndex;
+   if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
+-    for (i = 0; i < attIndex; i += 2)
+-      if (appAtts[i] == elementType->idAtt->name) {
+-        parser->m_idAttIndex = i;
++    for (size_t k = 0; k < attIndex; k += 2)
++      if (appAtts[k] == elementType->idAtt->name) {
++        if (k > INT_MAX)
++          return XML_ERROR_NO_MEMORY;
++        parser->m_idAttIndex = (int)k;
+         break;
+       }
+   } else
+@@ -4132,7 +4137,7 @@
+ 
+   /* expand prefixed attribute names, check for duplicates,
+      and clear flags that say whether attributes were specified */
+-  i = 0;
++  size_t ai = 0;
+   if (nPrefixes) {
+     int j; /* hash table index */
+     unsigned long version = parser->m_nsAttsVersion;
+@@ -4194,8 +4199,8 @@
+     parser->m_nsAttsVersion = --version;
+ 
+     /* expand prefixed names and check for duplicates */
+-    for (; i < attIndex; i += 2) {
+-      const XML_Char *s = appAtts[i];
++    for (; ai < attIndex; ai += 2) {
++      const XML_Char *s = appAtts[ai];
+       if (s[-1] == 2) { /* prefixed */
+         ATTRIBUTE_ID *id;
+         const BINDING *b;
+@@ -4284,7 +4289,7 @@
+         /* store expanded name in attribute list */
+         s = poolStart(&parser->m_tempPool);
+         poolFinish(&parser->m_tempPool);
+-        appAtts[i] = s;
++        appAtts[ai] = s;
+ 
+         /* fill empty slot with new version, uriName and hash value */
+         parser->m_nsAtts[j].version = version;
+@@ -4292,7 +4297,7 @@
+         parser->m_nsAtts[j].uriName = s;
+ 
+         if (! --nPrefixes) {
+-          i += 2;
++          ai += 2;
+           break;
+         }
+       } else                     /* not prefixed */
+@@ -4300,8 +4305,8 @@
+     }
+   }
+   /* clear flags for the remaining attributes */
+-  for (; i < attIndex; i += 2)
+-    ((XML_Char *)(appAtts[i]))[-1] = 0;
++  for (; ai < attIndex; ai += 2)
++    ((XML_Char *)(appAtts[ai]))[-1] = 0;
+   for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
+     binding->attId->name[-1] = 0;
+ 
diff -urN old/debian/patches/series new/debian/patches/series
--- old/debian/patches/series	2026-10-21 18:22:05.000000000 -0400
+++ new/debian/patches/series	2026-11-05 15:18:31.000000000 -0500
@@ -68,3 +68,7 @@
 CVE-2026-118370.patch
+CVE-2026-117610.patch
+CVE-2025-59375-tests.patch
+CVE-2026-113351.patch

Reply via email to