git: 32652bf4040c - stable/15 - contrib/expat: import expat 2.8.2

From: Philip Paeps <philip_at_FreeBSD.org>
Date: Thu, 02 Jul 2026 04:14:59 UTC
The branch stable/15 has been updated by philip:

URL: https://cgit.FreeBSD.org/src/commit/?id=32652bf4040ca010924f05e0fce4326b62709c11

commit 32652bf4040ca010924f05e0fce4326b62709c11
Author:     Philip Paeps <philip@FreeBSD.org>
AuthorDate: 2026-06-25 14:34:28 +0000
Commit:     Philip Paeps <philip@FreeBSD.org>
CommitDate: 2026-07-02 03:06:35 +0000

    contrib/expat: import expat 2.8.2
    
    Changes: https://github.com/libexpat/libexpat/blob/R_2_8_2/expat/Changes
    
    Security:       CVE-2026-50219
    Security:       CVE-2026-56131
    Security:       CVE-2026-56132
    Security:       CVE-2026-56403
    Security:       CVE-2026-56404
    Security:       CVE-2026-56405
    Security:       CVE-2026-56406
    Security:       CVE-2026-56407
    Security:       CVE-2026-56408
    Security:       CVE-2026-56409
    Security:       CVE-2026-56410
    Security:       CVE-2026-56411
    Security:       CVE-2026-56412
    
    (cherry picked from commit c82aeee8a6d39371006f5eeb1b51704e7b97e2b7)
---
 contrib/expat/Changes                     |   92 ++-
 contrib/expat/README.md                   |    5 +-
 contrib/expat/configure.ac                |   23 +-
 contrib/expat/doc/reference.html          |    6 +-
 contrib/expat/doc/xmlwf.1                 |    2 +-
 contrib/expat/doc/xmlwf.xml               |    2 +-
 contrib/expat/lib/Makefile.am             |    5 +
 contrib/expat/lib/Makefile.in             |    5 +
 contrib/expat/lib/expat.h                 |    2 +-
 contrib/expat/lib/fallthrough.h           |   49 ++
 contrib/expat/lib/memory_sanitizer.h      |   51 ++
 contrib/expat/lib/random_arc4random_buf.c |    4 +
 contrib/expat/lib/random_dev_urandom.c    |    4 +-
 contrib/expat/lib/random_getentropy.c     |    8 +-
 contrib/expat/lib/random_getrandom.c      |   11 +-
 contrib/expat/lib/siphash.h               |   15 +-
 contrib/expat/lib/xcsinc.c                |   48 ++
 contrib/expat/lib/xmlparse.c              | 1208 ++++++++++++++++-------------
 contrib/expat/lib/xmltok.c                |    6 +-
 contrib/expat/lib/xmltok_impl.c           |   21 +-
 contrib/expat/tests/acc_tests.c           |    6 +-
 contrib/expat/tests/alloc_tests.c         |    6 +-
 contrib/expat/tests/basic_tests.c         |   48 +-
 contrib/expat/tests/chardata.c            |   14 +-
 contrib/expat/tests/common.c              |    5 +-
 contrib/expat/tests/handlers.c            |   53 +-
 contrib/expat/tests/handlers.h            |   14 +
 contrib/expat/tests/misc_tests.c          |   42 +-
 contrib/expat/xmlwf/filemap.h             |    3 +-
 contrib/expat/xmlwf/win32filemap.c        |    2 +-
 contrib/expat/xmlwf/xmlfile.c             |   18 +-
 contrib/expat/xmlwf/xmlwf.c               |  107 ++-
 contrib/expat/xmlwf/xmlwf_helpgen.py      |    2 +-
 lib/libexpat/expat_config.h               |    6 +-
 lib/libexpat/libbsdxml.3                  |    4 +-
 35 files changed, 1234 insertions(+), 663 deletions(-)

diff --git a/contrib/expat/Changes b/contrib/expat/Changes
index 313b3dc60cd0..6a1b89160fb9 100644
--- a/contrib/expat/Changes
+++ b/contrib/expat/Changes
@@ -29,6 +29,94 @@
 !! THANK YOU!                        Sebastian Pipping -- Berlin, 2026-03-17 !!
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
+Release 2.8.2 Thu June 25 2026
+        Security fixes:
+           #1246  CVE-2026-50219 -- Disallow calls to functions
+                    `XML_GetBuffer`, `XML_Parse`, `XML_ParseBuffer`,
+                    `XML_ParserFree`, `XML_ParserReset` to guard e.g.
+                    Expat bindings from memory corruption;
+                    this CPython issue is related:
+                    https://github.com/python/cpython/issues/146169
+           #1267  CVE-2026-56131 -- Protect XML_ResumeParser from being called
+                                    from a handler, plugging a hole in the fix
+                                    to CVE-2026-50219
+           #1272  CVE-2026-56132 -- Fix out-of-bound scaffolding index store
+                                    in `doProlog`
+     #1229 #1232  CVE-2026-56403 -- Integer overflow in `storeAtts`
+           #1249  CVE-2026-56404 -- Integer overflow in `addBinding`
+           #1251  CVE-2026-56405 -- Integer overflow in `getAttributeId`
+           #1255  CVE-2026-56406 -- Integer overflow in `XML_ParseBuffer`
+           #1262  CVE-2026-56407 -- Integer overflow in `textLen` handling
+            #565  CVE-2026-56408 -- Integer overflow in `copyString`
+                    (commit 16e2efd867ea8567ffa012210b52ef5918e20817)
+           #1259  CVE-2026-56409 -- xmlwf: Integer overflow in output path join
+           #1252  CVE-2026-56410 -- xmlwf: Integer overflow in
+                    `resolveSystemId`
+           #1263  CVE-2026-56411 -- xmlwf: Integer overflow in notation list
+                    allocation
+           #1278  CVE-2026-56412 -- Guard XML_TOK_DATA_CHARS handler calls in
+                    `doCdataSection`, plugging a hole in the fix to
+                    CVE-2026-50219
+
+        Bug fixes:
+           #1260  xmlwf: Escape names and base URI in meta output
+           #1266  xmlwf: Pick a safe quote for notation system and public IDs
+
+        Other changes:
+           #1257  CMake|Autotools: Stop using /dev/urandom by default
+     #1244 #1254  CMake: Fix guard for Unix sources of entropy
+     #1183 #1270  CMake|Windows: Add missing export for symbol
+                                 `XML_SetHashSalt16Bytes`
+           #1236  CMake: Mark option EXPAT_OSSFUZZ_BUILD as advanced
+           #1283  Limit output indentation for EXPAT_ENTITY_DEBUG=1 and
+                    allow unlimited indentation via EXPAT_ENTITY_DEBUG=2
+            #565  Replace some loops by use of `memcpy`, `strlen`, `wcslen`
+           #1220  lib: Use a size_t for group sizes
+           #1221  lib: Fix too-conservative integer overflow check when
+                       appending raw name
+           #1222  lib: Simplify attribute allocation/management logic
+           #1224  Update fallthrough annotations to satisfy Clang and GCC
+           #1226  lib: Remove unnecessary void * casts in random code
+           #1228  lib: Reduce scope of locals in storeAtts
+           #1230  lib: Count attributes with size_t variables
+           #1238  Minor get-buffer improvements
+     #1239 #1240  lib|tests: Include header expat_config.h first
+           #1241  lib: Shrink size of XML_GetBuffer
+           #1242  lib: Remove a legacy comment
+           #1243  lib: XML_ParserReset: Extract repeated linked-list move logic
+           #1243  lib: Unify entity free lists
+           #1247  lib: Fix use of '0' as boolean literal
+           #1248  lib: Make XML_Index overflow check more intuitive
+           #1256  lib: Use size_t for counting string/URI lengths
+           #1258  lib: XML_GetInputContext: Remove use of 0 for NULL
+           #1261  Comment typo fixes
+           #1275  Teach Memory Sanitizer semantics of randomization functions
+     #1276 #1281  Version info bumped from 13:1:12 (libexpat*.so.1.12.1)
+                    to 13:2:12 (libexpat*.so.1.12.2); see https://verbump.de/
+                    for what these numbers do
+
+        Infrastructure:
+           #1231  perl-integration.yml: Bump to XML::Parser 2.59
+           #1237  emscripten.yml: Bump from Ubuntu 22.04 to 24.04
+     #1183 #1271  windows-build.yml: Cover completeness of file
+                                     libexpat.def.cmake
+           #1274  linux.yml: Make llvm-symbolizer available in CI
+
+        Special thanks to:
+            Alessandro Gario
+            Asher Darden
+            Christoph Reiter
+            Haris Hussain
+            Matthew Fernandez
+            Kartik Kenchi
+            Nick Begg
+            Sajin S
+            Yousef Shanableh
+                 and
+            Anthropic
+            Astra Security
+            Trail of Bits
+
 Release 2.8.1 Sun May 10 2026
         Security fixes:
            #1216  CVE-2026-45186 -- Fix quadratic runtime from attribute name
@@ -1820,7 +1908,7 @@ Release 2.1.0 Sat March 24 2012
         - Bug Fixes:
           #1742315: Harmful XML_ParserCreateNS suggestion.
           #1785430: Expat build fails on linux-amd64 with gcc version>=4.1 -O3.
-          #1983953, 2517952, 2517962, 2649838: 
+          #1983953, 2517952, 2517962, 2649838:
                 Build modifications using autoreconf instead of buildconf.sh.
           #2815947, #2884086: OBJEXT and EXEEXT support while building.
           #2517938: xmlwf should return non-zero exit status if not well-formed.
@@ -1846,7 +1934,7 @@ Release 2.1.0 Sat March 24 2012
                 See bug #2990652 and patch #3312568.
           Added run-benchmark target to Makefile.in - relies on testdata module
                 present in the same relative location as in the repository.
-          
+
 Release 2.0.1 Tue June 5 2007
         - Fixed bugs #1515266, #1515600: The character data handler's calling
           of XML_StopParser() was not handled properly; if the parser was
diff --git a/contrib/expat/README.md b/contrib/expat/README.md
index 7a5ed463b6d5..5ad5e1e85afa 100644
--- a/contrib/expat/README.md
+++ b/contrib/expat/README.md
@@ -11,7 +11,7 @@
 > at the top of the `Changes` file.
 
 
-# Expat, Release 2.8.1
+# Expat, Release 2.8.2
 
 This is Expat, a C99 library for parsing
 [XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by
@@ -286,9 +286,6 @@ EXPAT_ENABLE_INSTALL:BOOL=ON
 // Use /MT flag (static CRT) when compiling in MSVC
 EXPAT_MSVC_STATIC_CRT:BOOL=OFF
 
-// Build fuzzers via OSS-Fuzz for the expat library
-EXPAT_OSSFUZZ_BUILD:BOOL=OFF
-
 // Build a shared expat library
 EXPAT_SHARED_LIBS:BOOL=ON
 
diff --git a/contrib/expat/configure.ac b/contrib/expat/configure.ac
index fb492dfd79f7..f14c0308e1c4 100644
--- a/contrib/expat/configure.ac
+++ b/contrib/expat/configure.ac
@@ -90,7 +90,7 @@ dnl If the API changes incompatibly set LIBAGE back to 0
 dnl
 
 LIBCURRENT=13  # sync
-LIBREVISION=1  # with
+LIBREVISION=2  # with
 LIBAGE=12      # CMakeLists.txt!
 
 AC_CONFIG_HEADERS([expat_config.h])
@@ -395,8 +395,23 @@ AC_DEFINE([XML_GE], 1,
           [Define as 1/0 to enable/disable support for general entities.])
 AC_DEFINE([XML_DTD], 1,
           [Define to make parameter entity parsing functionality available.])
-AC_DEFINE([XML_DEV_URANDOM], 1,
-          [Define to include code reading entropy from `/dev/urandom'.])
+
+
+have_dev_urandom=false
+
+AC_ARG_WITH([dev-urandom],
+  [AS_HELP_STRING([--with-dev-urandom],
+                  [enforce the use of /dev/urandom in the system @<:@default=no@:>@])
+AS_HELP_STRING([--without-dev-urandom],
+               [enforce not using /dev/urandom in the system @<:@default=no@:>@])],
+  [with_dev_urandom=${withval}],
+  [])
+
+AS_IF([test "x${with_dev_urandom}" = "xyes"],
+  [have_dev_urandom=true
+   AC_DEFINE([XML_DEV_URANDOM], 1,
+             [Define to include code reading entropy from `/dev/urandom'.])])
+
 
 AC_ARG_ENABLE([xml-attr-info],
   [AS_HELP_STRING([--enable-xml-attr-info],
@@ -580,7 +595,7 @@ Entropy sources:
              getentropy: ${have_getentropy}
               getrandom: ${have_getrandom_function}
   syscall SYS_getrandom: ${have_getrandom_syscall}
-           /dev/urandom: true
+           /dev/urandom: ${have_dev_urandom}
 
 Continue with e.g.:
   make -j2
diff --git a/contrib/expat/doc/reference.html b/contrib/expat/doc/reference.html
index 07d331ed7b56..5c4b1c76ca78 100644
--- a/contrib/expat/doc/reference.html
+++ b/contrib/expat/doc/reference.html
@@ -53,7 +53,7 @@
   <body>
     <div>
       <h1>
-        The Expat XML Parser <small>Release 2.8.1</small>
+        The Expat XML Parser <small>Release 2.8.2</small>
       </h1>
     </div>
 
@@ -1602,7 +1602,9 @@ XML_ParserReset(XML_Parser p,
         To state the obvious: the three parsing functions <code><a href=
         "#XML_Parse">XML_Parse</a></code>, <code><a href=
         "#XML_ParseBuffer">XML_ParseBuffer</a></code> and <code><a href=
-        "#XML_GetBuffer">XML_GetBuffer</a></code> must not be called from within a
+        "#XML_GetBuffer">XML_GetBuffer</a></code> as well as the two cleanup functions
+        <code><a href="#XML_ParserFree">XML_ParserFree</a></code> and <code><a href=
+        "#XML_ParserReset">XML_ParserReset</a></code> must not be called from within a
         handler unless they operate on a separate parser instance, that is, one that did
         not call the handler. For example, it is OK to call the parsing functions from
         within an <code>XML_ExternalEntityRefHandler</code>, if they apply to the parser
diff --git a/contrib/expat/doc/xmlwf.1 b/contrib/expat/doc/xmlwf.1
index 12760944a5da..3de559ec1bb3 100644
--- a/contrib/expat/doc/xmlwf.1
+++ b/contrib/expat/doc/xmlwf.1
@@ -5,7 +5,7 @@
 \\$2 \(la\\$1\(ra\\$3
 ..
 .if \n(.g .mso www.tmac
-.TH XMLWF 1 "May 10, 2026" "" ""
+.TH XMLWF 1 "June 25, 2026" "" ""
 .SH NAME
 xmlwf \- Determines if an XML document is well-formed
 .SH SYNOPSIS
diff --git a/contrib/expat/doc/xmlwf.xml b/contrib/expat/doc/xmlwf.xml
index 529dbba16722..7e57cf1346b9 100644
--- a/contrib/expat/doc/xmlwf.xml
+++ b/contrib/expat/doc/xmlwf.xml
@@ -21,7 +21,7 @@
           "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
   <!ENTITY dhfirstname "<firstname>Scott</firstname>">
   <!ENTITY dhsurname   "<surname>Bronson</surname>">
-  <!ENTITY dhdate      "<date>May 10, 2026</date>">
+  <!ENTITY dhdate      "<date>June 25, 2026</date>">
   <!-- Please adjust this^^ date whenever cutting a new release. -->
   <!ENTITY dhsection   "<manvolnum>1</manvolnum>">
   <!ENTITY dhemail     "<email>bronson@rinspin.com</email>">
diff --git a/contrib/expat/lib/Makefile.am b/contrib/expat/lib/Makefile.am
index 27bf2ab64769..2b6aec2e6bdc 100644
--- a/contrib/expat/lib/Makefile.am
+++ b/contrib/expat/lib/Makefile.am
@@ -10,6 +10,8 @@
 # Copyright (c) 2017      Tomasz Kłoczko <kloczek@fedoraproject.org>
 # Copyright (c) 2019      David Loffredo <loffredo@steptools.com>
 # Copyright (c) 2026      Gordon Messmer <gordon.messmer@gmail.com>
+# Copyright (c) 2026      Nick Begg <nick@stunttruck.net>
+# Copyright (c) 2026      Matthew Fernandez <matthew.fernandez@gmail.com>
 # Licensed under the MIT license:
 #
 # Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -112,14 +114,17 @@ EXTRA_DIST = \
     asciitab.h \
     expat_external.h \
     expat.h \
+    fallthrough.h \
     iasciitab.h \
     internal.h \
     latin1tab.h \
     libexpat.def.cmake \
+    memory_sanitizer.h \
     nametab.h \
     siphash.h \
     utf8tab.h \
     winconfig.h \
+    xcsinc.c \
     xmlrole.h \
     xmltok.h \
     xmltok_impl.c \
diff --git a/contrib/expat/lib/Makefile.in b/contrib/expat/lib/Makefile.in
index 4cd6fcfc6088..73db0e584705 100644
--- a/contrib/expat/lib/Makefile.in
+++ b/contrib/expat/lib/Makefile.in
@@ -26,6 +26,8 @@
 # Copyright (c) 2017      Tomasz Kłoczko <kloczek@fedoraproject.org>
 # Copyright (c) 2019      David Loffredo <loffredo@steptools.com>
 # Copyright (c) 2026      Gordon Messmer <gordon.messmer@gmail.com>
+# Copyright (c) 2026      Nick Begg <nick@stunttruck.net>
+# Copyright (c) 2026      Matthew Fernandez <matthew.fernandez@gmail.com>
 # Licensed under the MIT license:
 #
 # Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -508,14 +510,17 @@ EXTRA_DIST = \
     asciitab.h \
     expat_external.h \
     expat.h \
+    fallthrough.h \
     iasciitab.h \
     internal.h \
     latin1tab.h \
     libexpat.def.cmake \
+    memory_sanitizer.h \
     nametab.h \
     siphash.h \
     utf8tab.h \
     winconfig.h \
+    xcsinc.c \
     xmlrole.h \
     xmltok.h \
     xmltok_impl.c \
diff --git a/contrib/expat/lib/expat.h b/contrib/expat/lib/expat.h
index ec3f58544cb0..c493c70441c4 100644
--- a/contrib/expat/lib/expat.h
+++ b/contrib/expat/lib/expat.h
@@ -1094,7 +1094,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
 */
 #  define XML_MAJOR_VERSION 2
 #  define XML_MINOR_VERSION 8
-#  define XML_MICRO_VERSION 1
+#  define XML_MICRO_VERSION 2
 
 #  ifdef __cplusplus
 }
diff --git a/contrib/expat/lib/fallthrough.h b/contrib/expat/lib/fallthrough.h
new file mode 100644
index 000000000000..707dbdd44bfe
--- /dev/null
+++ b/contrib/expat/lib/fallthrough.h
@@ -0,0 +1,49 @@
+/*
+                            __  __            _
+                         ___\ \/ /_ __   __ _| |_
+                        / _ \\  /| '_ \ / _` | __|
+                       |  __//  \| |_) | (_| | |_
+                        \___/_/\_\ .__/ \__,_|\__|
+                                 |_| XML parser
+
+   Copyright (c) 2026 Nick Begg <nick@stunttruck.net>
+   Licensed under the MIT license:
+
+   Permission is  hereby granted,  free of charge,  to any  person obtaining
+   a  copy  of  this  software   and  associated  documentation  files  (the
+   "Software"),  to  deal in  the  Software  without restriction,  including
+   without  limitation the  rights  to use,  copy,  modify, merge,  publish,
+   distribute, sublicense, and/or sell copies of the Software, and to permit
+   persons  to whom  the Software  is  furnished to  do so,  subject to  the
+   following conditions:
+
+   The above copyright  notice and this permission notice  shall be included
+   in all copies or substantial portions of the Software.
+
+   THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
+   EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+   NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+   DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
+   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+   USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef FALLTHROUGH_H
+#  define FALLTHROUGH_H 1
+
+// Explicit fallthrough in switch case to avoid warnings
+// with compiler flag -Wimplicit-fallthrough.
+
+#  define EXPAT_FALLTHROUGH                                                    \
+    do {                                                                       \
+    } while (0)
+
+#  if defined(__has_attribute)
+#    if __has_attribute(fallthrough)
+#      undef EXPAT_FALLTHROUGH
+#      define EXPAT_FALLTHROUGH __attribute__((fallthrough))
+#    endif
+#  endif
+
+#endif // FALLTHROUGH_H
diff --git a/contrib/expat/lib/memory_sanitizer.h b/contrib/expat/lib/memory_sanitizer.h
new file mode 100644
index 000000000000..a8a8006ccded
--- /dev/null
+++ b/contrib/expat/lib/memory_sanitizer.h
@@ -0,0 +1,51 @@
+/*
+                            __  __            _
+                         ___\ \/ /_ __   __ _| |_
+                        / _ \\  /| '_ \ / _` | __|
+                       |  __//  \| |_) | (_| | |_
+                        \___/_/\_\ .__/ \__,_|\__|
+                                 |_| XML parser
+
+   Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@gmail.com>
+   Licensed under the MIT license:
+
+   Permission is  hereby granted,  free of charge,  to any  person obtaining
+   a  copy  of  this  software   and  associated  documentation  files  (the
+   "Software"),  to  deal in  the  Software  without restriction,  including
+   without  limitation the  rights  to use,  copy,  modify, merge,  publish,
+   distribute, sublicense, and/or sell copies of the Software, and to permit
+   persons  to whom  the Software  is  furnished to  do so,  subject to  the
+   following conditions:
+
+   The above copyright  notice and this permission notice  shall be included
+   in all copies or substantial portions of the Software.
+
+   THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
+   EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+   NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+   DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
+   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+   USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if ! defined(MEMORY_SANITIZER_H)
+#  define MEMORY_SANITIZER_H 1
+
+#  if defined(__has_feature)
+#    if __has_feature(memory_sanitizer)
+#      include <sanitizer/msan_interface.h>
+
+// inform Memory Sanitizer that [base, base + extent) is now initialized
+#      define MSAN_UNPOISON(base, extent) __msan_unpoison((base), (extent))
+
+#    endif
+#  endif
+
+#  if ! defined(MSAN_UNPOISON)
+#    define MSAN_UNPOISON(base, extent)                                        \
+      do {                                                                     \
+      } while (0)
+#  endif
+
+#endif // ! defined(MEMORY_SANITIZER_H)
diff --git a/contrib/expat/lib/random_arc4random_buf.c b/contrib/expat/lib/random_arc4random_buf.c
index 1476f07ba1a2..5212b9f192ce 100644
--- a/contrib/expat/lib/random_arc4random_buf.c
+++ b/contrib/expat/lib/random_arc4random_buf.c
@@ -7,6 +7,7 @@
                                  |_| XML parser
 
    Copyright (c) 2026 Sebastian Pipping <sebastian@pipping.org>
+   Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@gmail.com>
    Licensed under the MIT license:
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -35,9 +36,12 @@
 #  define _DEFAULT_SOURCE 1 /* for glibc */
 #endif
 
+#include "memory_sanitizer.h"
 #include <stdlib.h> // for arc4random_buf
 
 void
 writeRandomBytes_arc4random_buf(void *target, size_t count) {
   arc4random_buf(target, count);
+  // MSan does not understand `arc4random_buf`, so explain its effects
+  MSAN_UNPOISON(target, count);
 }
diff --git a/contrib/expat/lib/random_dev_urandom.c b/contrib/expat/lib/random_dev_urandom.c
index e508fe9f3e3c..acae6ba4b047 100644
--- a/contrib/expat/lib/random_dev_urandom.c
+++ b/contrib/expat/lib/random_dev_urandom.c
@@ -49,11 +49,11 @@ writeRandomBytes_dev_urandom(void *target, size_t count) {
 
   const int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
   if (fd < 0) {
-    return 0;
+    return false;
   }
 
   do {
-    void *const currentTarget = (void *)((char *)target + bytesWrittenTotal);
+    void *const currentTarget = (char *)target + bytesWrittenTotal;
     const size_t bytesToWrite = count - bytesWrittenTotal;
 
     errno = 0;
diff --git a/contrib/expat/lib/random_getentropy.c b/contrib/expat/lib/random_getentropy.c
index b4be70ed73c1..5cea2d8838b9 100644
--- a/contrib/expat/lib/random_getentropy.c
+++ b/contrib/expat/lib/random_getentropy.c
@@ -7,6 +7,7 @@
                                  |_| XML parser
 
    Copyright (c) 2026 Sebastian Pipping <sebastian@pipping.org>
+   Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@gmail.com>
    Licensed under the MIT license:
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -45,10 +46,15 @@
 #  include <unistd.h>
 #endif // ! defined(__APPLE__)
 
+#include "memory_sanitizer.h"
 #include <errno.h>
 
 bool
 writeRandomBytes_getentropy(void *target, size_t count) {
   errno = 0;
-  return getentropy(target, count) == 0;
+  const bool success = getentropy(target, count);
+  // MSan does not understand `getentropy`, so explain its effects
+  if (success)
+    MSAN_UNPOISON(target, count);
+  return success;
 }
diff --git a/contrib/expat/lib/random_getrandom.c b/contrib/expat/lib/random_getrandom.c
index e5724a211cc6..72e2cc7093be 100644
--- a/contrib/expat/lib/random_getrandom.c
+++ b/contrib/expat/lib/random_getrandom.c
@@ -32,10 +32,10 @@
    USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "random_getrandom.h"
-
 #include "expat_config.h" // for HAVE_GETRANDOM, HAVE_SYSCALL_GETRANDOM
 
+#include "random_getrandom.h"
+
 #if defined(HAVE_GETRANDOM)
 #  include <sys/random.h> /* getrandom */
 #endif
@@ -52,6 +52,7 @@
 #  define GRND_NONBLOCK 0x0001
 #endif /* defined(GRND_NONBLOCK) */
 
+#include "memory_sanitizer.h"
 #include <assert.h>
 #include <errno.h>
 #include <limits.h> // for INT_MAX
@@ -64,7 +65,7 @@ writeRandomBytes_getrandom_nonblock(void *target, size_t count) {
   const unsigned int getrandomFlags = GRND_NONBLOCK;
 
   do {
-    void *const currentTarget = (void *)((char *)target + bytesWrittenTotal);
+    void *const currentTarget = (char *)target + bytesWrittenTotal;
     const size_t bytesToWrite = count - bytesWrittenTotal;
 
     assert(bytesToWrite <= INT_MAX);
@@ -74,9 +75,13 @@ writeRandomBytes_getrandom_nonblock(void *target, size_t count) {
     const int bytesWrittenMore =
 #if defined(HAVE_GETRANDOM)
         (int)getrandom(currentTarget, bytesToWrite, getrandomFlags);
+    // MSan understands `getrandom`, so does not need extra guidance
 #else
         (int)syscall(SYS_getrandom, currentTarget, bytesToWrite,
                      getrandomFlags);
+    // MSan does not understand `syscall`, so explain its effects
+    if (bytesWrittenMore > 0)
+      MSAN_UNPOISON(currentTarget, bytesWrittenMore);
 #endif
 
     if (bytesWrittenMore > 0) {
diff --git a/contrib/expat/lib/siphash.h b/contrib/expat/lib/siphash.h
index 04f6f74585b5..be216b4006dc 100644
--- a/contrib/expat/lib/siphash.h
+++ b/contrib/expat/lib/siphash.h
@@ -100,6 +100,7 @@
 
 #include <stddef.h> /* size_t */
 #include <stdint.h> /* uint64_t uint32_t uint8_t */
+#include "fallthrough.h"
 
 /*
  * Workaround to not require a C++11 compiler for using ULL suffix
@@ -234,25 +235,25 @@ sip24_final(struct siphash *H) {
   switch (left) {
   case 7:
     b |= (uint64_t)H->buf[6] << 48;
-    /* fall through */
+    EXPAT_FALLTHROUGH;
   case 6:
     b |= (uint64_t)H->buf[5] << 40;
-    /* fall through */
+    EXPAT_FALLTHROUGH;
   case 5:
     b |= (uint64_t)H->buf[4] << 32;
-    /* fall through */
+    EXPAT_FALLTHROUGH;
   case 4:
     b |= (uint64_t)H->buf[3] << 24;
-    /* fall through */
+    EXPAT_FALLTHROUGH;
   case 3:
     b |= (uint64_t)H->buf[2] << 16;
-    /* fall through */
+    EXPAT_FALLTHROUGH;
   case 2:
     b |= (uint64_t)H->buf[1] << 8;
-    /* fall through */
+    EXPAT_FALLTHROUGH;
   case 1:
     b |= (uint64_t)H->buf[0] << 0;
-    /* fall through */
+    EXPAT_FALLTHROUGH;
   case 0:
     break;
   }
diff --git a/contrib/expat/lib/xcsinc.c b/contrib/expat/lib/xcsinc.c
new file mode 100644
index 000000000000..3597c2480bc9
--- /dev/null
+++ b/contrib/expat/lib/xcsinc.c
@@ -0,0 +1,48 @@
+/* This file is included from other .c files!
+                            __  __            _
+                         ___\ \/ /_ __   __ _| |_
+                        / _ \\  /| '_ \ / _` | __|
+                       |  __//  \| |_) | (_| | |_
+                        \___/_/\_\ .__/ \__,_|\__|
+                                 |_| XML parser
+
+   Copyright (c) 2022 Sebastian Pipping <sebastian@pipping.org>
+   Licensed under the MIT license:
+
+   Permission is  hereby granted,  free of charge,  to any  person obtaining
+   a  copy  of  this  software   and  associated  documentation  files  (the
+   "Software"),  to  deal in  the  Software  without restriction,  including
+   without  limitation the  rights  to use,  copy,  modify, merge,  publish,
+   distribute, sublicense, and/or sell copies of the Software, and to permit
+   persons  to whom  the Software  is  furnished to  do so,  subject to  the
+   following conditions:
+
+   The above copyright  notice and this permission notice  shall be included
+   in all copies or substantial portions of the Software.
+
+   THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
+   EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+   NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+   DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
+   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+   USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+static size_t
+xcslen(const XML_Char *s) {
+#ifdef XML_UNICODE
+#  ifdef XML_UNICODE_WCHAR_T
+  return wcslen(s);
+#  else
+  // XML_Char is unsigned short
+  size_t len = 0;
+  while (s[len]) {
+    len++;
+  }
+  return len;
+#  endif
+#else
+  return strlen(s);
+#endif
+}
diff --git a/contrib/expat/lib/xmlparse.c b/contrib/expat/lib/xmlparse.c
index 890a9389f15d..60f6cc700548 100644
--- a/contrib/expat/lib/xmlparse.c
+++ b/contrib/expat/lib/xmlparse.c
@@ -1,4 +1,4 @@
-/* 75ef4224f81c052e9e5aeea2ac7de75357d2169ff9908e39edc08b9dc3052513 (2.8.1+)
+/* 5de44e6750c6cc78818f06ed552f522a1241df0299395250e1792cb339389daf (2.8.2+)
                             __  __            _
                          ___\ \/ /_ __   __ _| |_
                         / _ \\  /| '_ \ / _` | __|
@@ -47,6 +47,9 @@
    Copyright (c) 2026      Rosen Penev <rosenp@gmail.com>
    Copyright (c) 2026      Francesco Bertolaccini
    Copyright (c) 2026      Christian Ng <christianrng@berkeley.edu>
+   Copyright (c) 2026      Nick Begg <nick@stunttruck.net>
+   Copyright (c) 2026      Kartik Kenchi <netliomax25@gmail.com>
+   Copyright (c) 2026      Haris Hussain <hextheshadow0x@gmail.com>
    Licensed under the MIT license:
 
    Permission is  hereby granted,  free of charge,  to any  person obtaining
@@ -90,7 +93,7 @@
 #include <stddef.h>
 #include <string.h> /* memset(), memcpy() */
 #include <assert.h>
-#include <limits.h> /* INT_MAX, UINT_MAX */
+#include <limits.h> /* INT_MAX, LLONG_MAX, LONG_MAX, UINT_MAX */
 #include <stdio.h>  /* fprintf */
 #include <stdlib.h> /* getenv */
 #include <stdint.h> /* SIZE_MAX, uintptr_t */
@@ -114,6 +117,7 @@
 #include "ascii.h"
 #include "expat.h"
 #include "siphash.h"
+#include "xcsinc.c"
 
 #if defined(HAVE_ARC4RANDOM)
 #  include "random_arc4random.h"
@@ -156,7 +160,7 @@
       * Windows >=Vista (rand_s): _WIN32. \
     \
     If you insist on not using any of these, bypass this error by defining \
-    XML_POOR_ENTROPY; you have been warned. \
+    XML_POOR_ENTROPY and be vulnerable to hash flooding; you have been warned. \
     \
     If you have reasons to patch this detection code away or need changes \
     to the build system, please open a bug.  Thank you!
@@ -207,6 +211,12 @@ typedef char ICHAR;
 
 #endif
 
+#ifdef XML_LARGE_SIZE
+#  define XML_INDEX_MAX LLONG_MAX
+#else
+#  define XML_INDEX_MAX LONG_MAX
+#endif
+
 /* Round up n to be a multiple of sz, where sz is a power of 2. */
 #define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
 
@@ -270,8 +280,8 @@ typedef struct binding {
   struct binding *prevPrefixBinding;
   const struct attribute_id *attId;
   XML_Char *uri;
-  int uriLen;
-  int uriAlloc;
+  size_t uriLen;
+  size_t uriAlloc;
 } BINDING;
 
 typedef struct prefix {
@@ -283,9 +293,9 @@ typedef struct {
   const XML_Char *str;
   const XML_Char *localPart;
   const XML_Char *prefix;
-  int strLen;
-  int uriLen;
-  int prefixLen;
+  size_t strLen;
+  size_t uriLen;
+  size_t prefixLen;
 } TAG_NAME;
 
 /* TAG represents an open element.
@@ -384,8 +394,8 @@ typedef struct {
   const XML_Char *name;
   PREFIX *prefix;
   const ATTRIBUTE_ID *idAtt;
-  int nDefaultAtts;
-  int allocDefaultAtts;
+  size_t nDefaultAtts;
+  size_t allocDefaultAtts;
   DEFAULT_ATTRIBUTE *defaultAtts;
   HASH_TABLE defaultAttsNames;
 } ELEMENT_TYPE;
@@ -417,6 +427,7 @@ typedef struct {
   unsigned scaffCount;
   int scaffLevel;
   int *scaffIndex;
+  size_t scaffIndexSize;
 } DTD;
 
 enum EntityType {
@@ -588,6 +599,7 @@ static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
 static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
                                  const char *ptr, const char *end);
 static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
+static bool FASTCALL poolGrowUntil(STRING_POOL *pool, size_t needed);
 static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool,
                                                const XML_Char *s);
 static const XML_Char *FASTCALL poolCopyStringNoFinish(STRING_POOL *pool,
@@ -642,16 +654,40 @@ static XML_Parser getRootParserOf(XML_Parser parser,
 static unsigned long getDebugLevel(const char *variableName,
                                    unsigned long defaultDebugLevel);
 
+static bool poolAppendChar(STRING_POOL *pool, XML_Char c);
+
+static bool poolAppendChars(STRING_POOL *pool, const XML_Char *s, size_t len);
+
 #define poolStart(pool) ((pool)->start)
 #define poolLength(pool) ((pool)->ptr - (pool)->start)
 #define poolChop(pool) ((void)--(pool->ptr))
 #define poolLastChar(pool) (((pool)->ptr)[-1])
 #define poolDiscard(pool) ((pool)->ptr = (pool)->start)
 #define poolFinish(pool) ((pool)->start = (pool)->ptr)
-#define poolAppendChar(pool, c)                                                \
-  (((pool)->ptr == (pool)->end && ! poolGrow(pool))                            \
-       ? 0                                                                     \
-       : ((*((pool)->ptr)++ = c), 1))
+
+bool
+poolAppendChar(STRING_POOL *pool, XML_Char c) {
+  if (pool->ptr == pool->end && ! poolGrow(pool))
+    return false;
+
+  *(pool->ptr)++ = c;
+  return true;
+}
+
+bool
+poolAppendChars(STRING_POOL *pool, const XML_Char *s, size_t len) {
+  // Detect and prevent integer overflow
+  if (len > SIZE_MAX / sizeof(XML_Char))
+    return false;
+
+  if (! poolGrowUntil(pool, len))
+    return false;
+
+  memcpy(pool->ptr, s, len * sizeof(XML_Char));
+  pool->ptr += len;
+
+  return true;
+}
 
 #if ! defined(XML_TESTING)
 const
@@ -730,11 +766,9 @@ struct XML_ParserStruct {
   const char *m_eventEndPtr;
   const char *m_positionPtr;
   OPEN_INTERNAL_ENTITY *m_openInternalEntities;
-  OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
   OPEN_INTERNAL_ENTITY *m_openAttributeEntities;
-  OPEN_INTERNAL_ENTITY *m_freeAttributeEntities;
   OPEN_INTERNAL_ENTITY *m_openValueEntities;
-  OPEN_INTERNAL_ENTITY *m_freeValueEntities;
+  OPEN_INTERNAL_ENTITY *m_freeEntities;
   XML_Bool m_defaultExpandInternalEntities;
   int m_tagLevel;
   ENTITY *m_declEntity;
@@ -754,7 +788,7 @@ struct XML_ParserStruct {
   TAG *m_freeTagList;
   BINDING *m_inheritedBindings;
   BINDING *m_freeBindingList;
-  int m_attsSize;
+  size_t m_attsSize;
   int m_nSpecifiedAtts;
   int m_idAttIndex;
   ATTRIBUTE *m_atts;
@@ -768,7 +802,7 @@ struct XML_ParserStruct {
   STRING_POOL m_tempPool;
   STRING_POOL m_temp2Pool;
   char *m_groupConnector;
-  unsigned int m_groupSize;
+  size_t m_groupSize;
   XML_Char m_namespaceSeparator;
   XML_Parser m_parentParser;
   XML_ParsingStatus m_parsingStatus;
@@ -785,6 +819,7 @@ struct XML_ParserStruct {
   ENTITY_STATS m_entity_stats;
 #endif
   XML_Bool m_reenter;
+  unsigned m_handlerCallDepth;
 };
 
 #if XML_GE == 1
@@ -1128,6 +1163,23 @@ generate_hash_secret_salt(void) {
 #endif
 }
 
+static void
+beforeHandler(XML_Parser parser) {
+  assert(parser->m_handlerCallDepth < UINT_MAX);
+  parser->m_handlerCallDepth++;
+}
+
+static void
+afterHandler(XML_Parser parser) {
+  assert(parser->m_handlerCallDepth > 0);
+  parser->m_handlerCallDepth--;
+}
+
+static bool
+isCalledFromInsideHandler(XML_Parser parser) {
+  return parser->m_handlerCallDepth > 0;
+}
+
 static enum XML_Error
 callProcessor(XML_Parser parser, const char *start, const char *end,
               const char **endPtr) {
@@ -1364,9 +1416,7 @@ parserCreate(const XML_Char *encodingName,
 
   parser->m_freeBindingList = NULL;
   parser->m_freeTagList = NULL;
-  parser->m_freeInternalEntities = NULL;
-  parser->m_freeAttributeEntities = NULL;
-  parser->m_freeValueEntities = NULL;
+  parser->m_freeEntities = NULL;
 
   parser->m_groupSize = 0;
   parser->m_groupConnector = NULL;
@@ -1482,6 +1532,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
   parser->m_parsingStatus.parsing = XML_INITIALIZED;
   // Reentry can only be triggered inside m_processor calls
   parser->m_reenter = XML_FALSE;
+  parser->m_handlerCallDepth = 0;
 #ifdef XML_DTD
   parser->m_isParamEntity = XML_FALSE;
   parser->m_useForeignDTD = XML_FALSE;
@@ -1515,12 +1566,22 @@ moveToFreeBindingList(XML_Parser parser, BINDING *bindings) {
   }
 }
 
+/* Moves a list of entities onto the start of another list. */
+static void
+moveEntityList(OPEN_INTERNAL_ENTITY **dst, OPEN_INTERNAL_ENTITY **src) {
+  for (OPEN_INTERNAL_ENTITY *head = *src; head != NULL;) {
+    OPEN_INTERNAL_ENTITY *const openEntity = head;
+    head = head->next;
+    openEntity->next = *dst;
+    *dst = openEntity;
+  }
+}
+
 XML_Bool XMLCALL
 XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
   TAG *tStk;
-  OPEN_INTERNAL_ENTITY *openEntityList;
 
-  if (parser == NULL)
+  if ((parser == NULL) || isCalledFromInsideHandler(parser))
     return XML_FALSE;
 
   if (parser->m_parentParser)
@@ -1535,32 +1596,14 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
     tag->bindings = NULL;
     parser->m_freeTagList = tag;
   }
-  /* move m_openInternalEntities to m_freeInternalEntities */
-  openEntityList = parser->m_openInternalEntities;
-  while (openEntityList) {
-    OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
-    openEntityList = openEntity->next;
-    openEntity->next = parser->m_freeInternalEntities;
-    parser->m_freeInternalEntities = openEntity;
-  }
-  /* move m_openAttributeEntities to m_freeAttributeEntities (i.e. same task but
-   * for attributes) */
*** 3286 LINES SKIPPED ***