Commit 62d4d33 for mammothjs

commit 62d4d33f71b17829f63d408ebe0f4c5eb560307e
Author: Michael Williamson <mike@zwobble.org>
Date:   Sat Sep 12 09:52:19 2026 +0100

    Handle missing complex field start characters

diff --git a/NEWS b/NEWS
index 77f348b..28bdbaa 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,9 @@
   Note that it is still strongly recommended to process untrusted documents in
   a separate thread with a timeout to avoid potential similar issues.

+* Handle complex field separator and end characters without corresponding start
+  characters.
+
 # 1.12.2

 * Avoid prototype pollution when reading the styles defined in a document. This
diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js
index 2ec9d0d..2c2a741 100644
--- a/lib/docx/body-reader.js
+++ b/lib/docx/body-reader.js
@@ -169,6 +169,12 @@ function BodyReader(options) {
             complexFieldStack.push({type: "begin", fldChar: element});
             currentInstrText = [];
         } else if (type === "end") {
+            if (complexFieldStack.length === 0) {
+                return emptyResultWithMessages([warning(
+                    "ignoring complex field end character without corresponding start character"
+                )]);
+            }
+
             var complexFieldEnd = complexFieldStack.pop();
             if (complexFieldEnd.type === "begin") {
                 complexFieldEnd = parseCurrentInstrText(complexFieldEnd);
@@ -179,6 +185,12 @@ function BodyReader(options) {
                 }));
             }
         } else if (type === "separate") {
+            if (complexFieldStack.length === 0) {
+                return emptyResultWithMessages([warning(
+                    "ignoring complex field separator character without corresponding start character"
+                )]);
+            }
+
             var complexFieldSeparate = complexFieldStack.pop();
             var complexField = parseCurrentInstrText(complexFieldSeparate);
             complexFieldStack.push(complexField);
diff --git a/test/docx/body-reader.tests.js b/test/docx/body-reader.tests.js
index 9559809..d8b521c 100644
--- a/test/docx/body-reader.tests.js
+++ b/test/docx/body-reader.tests.js
@@ -581,6 +581,32 @@ test("complex fields", (function() {
                 }),
                 isEmptyRun
             ));
+        },
+
+        "separator character without corresponding start character is ignored": function() {
+            var paragraphXml = new XmlElement("w:p", {}, [
+                separateXml
+            ]);
+
+            var result = readXmlElement(paragraphXml);
+
+            assertThat(result.value.children, contains(
+                isEmptyRun
+            ));
+            assert.deepEqual(result.messages, [warning("ignoring complex field separator character without corresponding start character")]);
+        },
+
+        "end character without corresponding start character is ignored": function() {
+            var paragraphXml = new XmlElement("w:p", {}, [
+                endXml
+            ]);
+
+            var result = readXmlElement(paragraphXml);
+
+            assertThat(result.value.children, contains(
+                isEmptyRun
+            ));
+            assert.deepEqual(result.messages, [warning("ignoring complex field end character without corresponding start character")]);
         }
     };
 })());