@depup/mammoth 1.12.1-depup.0 → 1.12.3-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/NEWS CHANGED
@@ -1,3 +1,21 @@
1
+ # 1.12.3
2
+
3
+ * Avoid excessive backtracking when parsing an unterminated string with many
4
+ escape sequences. The previous behaviour would allow maliciously crafted
5
+ documents to cause a denial of service.
6
+
7
+ Note that it is still strongly recommended to process untrusted documents in
8
+ a separate thread with a timeout to avoid potential similar issues.
9
+
10
+ * Handle complex field separator and end characters without corresponding start
11
+ characters.
12
+
13
+ # 1.12.2
14
+
15
+ * Avoid prototype pollution when reading the styles defined in a document. This
16
+ avoids an issue where a maliciously crafted document could be used to set
17
+ externalFileAccess to true.
18
+
1
19
  # 1.12.1
2
20
 
3
21
  * Fix: on Windows, when an image's content type includes a backslash in the
package/README.md CHANGED
@@ -13,8 +13,8 @@ npm install @depup/mammoth
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [mammoth](https://www.npmjs.com/package/mammoth) @ 1.12.1 |
17
- | Processed | 2026-08-09 |
16
+ | Original | [mammoth](https://www.npmjs.com/package/mammoth) @ 1.12.3 |
17
+ | Processed | 2026-09-12 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 7 |
20
20
 
@@ -22,10 +22,10 @@ npm install @depup/mammoth
22
22
 
23
23
  | Dependency | From | To |
24
24
  |------------|------|-----|
25
- | @xmldom/xmldom | ^0.8.6 | ^0.9.10 |
26
- | argparse | ~1.0.3 | ^3.0.0 |
25
+ | @xmldom/xmldom | ^0.8.6 | ^0.9.12 |
26
+ | argparse | ~1.0.3 | ^3.0.2 |
27
27
  | bluebird | ~3.4.0 | ^3.7.2 |
28
- | jszip | ^3.7.1 | ^3.10.1 |
28
+ | jszip | ^3.7.1 | ^3.10.2 |
29
29
  | path-is-absolute | ^1.0.0 | ^2.0.0 |
30
30
  | underscore | ^1.13.1 | ^1.13.8 |
31
31
  | xmlbuilder | ^10.0.0 | ^15.1.1 |
package/changes.json CHANGED
@@ -2,11 +2,11 @@
2
2
  "bumped": {
3
3
  "@xmldom/xmldom": {
4
4
  "from": "^0.8.6",
5
- "to": "^0.9.10"
5
+ "to": "^0.9.12"
6
6
  },
7
7
  "argparse": {
8
8
  "from": "~1.0.3",
9
- "to": "^3.0.0"
9
+ "to": "^3.0.2"
10
10
  },
11
11
  "bluebird": {
12
12
  "from": "~3.4.0",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "jszip": {
16
16
  "from": "^3.7.1",
17
- "to": "^3.10.1"
17
+ "to": "^3.10.2"
18
18
  },
19
19
  "path-is-absolute": {
20
20
  "from": "^1.0.0",
@@ -29,6 +29,6 @@
29
29
  "to": "^15.1.1"
30
30
  }
31
31
  },
32
- "timestamp": "2026-08-09T16:09:15.209Z",
32
+ "timestamp": "2026-09-12T16:08:51.567Z",
33
33
  "totalUpdated": 7
34
34
  }
@@ -42,7 +42,7 @@ function DocumentConversion(options, comments) {
42
42
  function convertToHtml(document) {
43
43
  var messages = [];
44
44
 
45
- var html = elementToHtml(document, messages, {});
45
+ var html = elementToHtml(document, messages, Object.create(null));
46
46
 
47
47
  var deferredNodes = [];
48
48
  walkHtml(html, function(node) {
@@ -50,7 +50,7 @@ function DocumentConversion(options, comments) {
50
50
  deferredNodes.push(node);
51
51
  }
52
52
  });
53
- var deferredValues = {};
53
+ var deferredValues = Object.create(null);
54
54
  return promises.mapSeries(deferredNodes, function(deferred) {
55
55
  return deferred.value().then(function(value) {
56
56
  deferredValues[deferred.id] = value;
@@ -169,6 +169,12 @@ function BodyReader(options) {
169
169
  complexFieldStack.push({type: "begin", fldChar: element});
170
170
  currentInstrText = [];
171
171
  } else if (type === "end") {
172
+ if (complexFieldStack.length === 0) {
173
+ return emptyResultWithMessages([warning(
174
+ "Ignoring complex field end character without corresponding start character"
175
+ )]);
176
+ }
177
+
172
178
  var complexFieldEnd = complexFieldStack.pop();
173
179
  if (complexFieldEnd.type === "begin") {
174
180
  complexFieldEnd = parseCurrentInstrText(complexFieldEnd);
@@ -179,6 +185,12 @@ function BodyReader(options) {
179
185
  }));
180
186
  }
181
187
  } else if (type === "separate") {
188
+ if (complexFieldStack.length === 0) {
189
+ return emptyResultWithMessages([warning(
190
+ "Ignoring complex field separator character without corresponding start character"
191
+ )]);
192
+ }
193
+
182
194
  var complexFieldSeparate = complexFieldStack.pop();
183
195
  var complexField = parseCurrentInstrText(complexFieldSeparate);
184
196
  complexFieldStack.push(complexField);
@@ -14,9 +14,9 @@ exports.defaultContentTypes = contentTypes({}, {});
14
14
 
15
15
 
16
16
  function readContentTypesFromXml(element) {
17
- var extensionDefaults = {};
18
- var overrides = {};
19
-
17
+ var extensionDefaults = Object.create(null);
18
+ var overrides = Object.create(null);
19
+
20
20
  element.children.forEach(function(child) {
21
21
  if (child.name === "content-types:Default") {
22
22
  extensionDefaults[child.attributes.Extension] = child.attributes.ContentType;
@@ -41,7 +41,7 @@ function contentTypes(overrides, extensionDefaults) {
41
41
  } else {
42
42
  var pathParts = path.split(".");
43
43
  var extension = pathParts[pathParts.length - 1];
44
- if (extensionDefaults.hasOwnProperty(extension)) {
44
+ if (Object.prototype.hasOwnProperty.call(extensionDefaults, extension)) {
45
45
  return extensionDefaults[extension];
46
46
  } else {
47
47
  var fallback = fallbackContentTypes[extension.toLowerCase()];
@@ -54,5 +54,5 @@ function contentTypes(overrides, extensionDefaults) {
54
54
  }
55
55
  }
56
56
  };
57
-
57
+
58
58
  }
@@ -17,7 +17,7 @@ function Numbering(nums, abstractNums, styles) {
17
17
  );
18
18
 
19
19
  function findLevel(numId, level) {
20
- return findLevelWithSeenNumIds(numId, level, {});
20
+ return findLevelWithSeenNumIds(numId, level, Object.create(null));
21
21
  }
22
22
 
23
23
  function findLevelWithSeenNumIds(numId, level, seenNumIds) {
@@ -63,7 +63,7 @@ function readNumberingXml(root, options) {
63
63
  }
64
64
 
65
65
  function readAbstractNums(root) {
66
- var abstractNums = {};
66
+ var abstractNums = Object.create(null);
67
67
  root.getElementsByTagName("w:abstractNum").forEach(function(element) {
68
68
  var id = element.attributes["w:abstractNumId"];
69
69
  abstractNums[id] = readAbstractNum(element);
@@ -72,7 +72,7 @@ function readAbstractNums(root) {
72
72
  }
73
73
 
74
74
  function readAbstractNum(element) {
75
- var levels = {};
75
+ var levels = Object.create(null);
76
76
 
77
77
  // Some malformed documents define numbering levels without an index, and
78
78
  // reference the numbering using a w:numPr element without a w:ilvl child.
@@ -110,7 +110,7 @@ function readAbstractNum(element) {
110
110
  }
111
111
 
112
112
  function readNums(root) {
113
- var nums = {};
113
+ var nums = Object.create(null);
114
114
  root.getElementsByTagName("w:num").forEach(function(element) {
115
115
  var numId = element.attributes["w:numId"];
116
116
  var abstractNumId = element.first("w:abstractNumId").attributes["w:val"];
@@ -19,12 +19,12 @@ function readRelationships(element) {
19
19
  }
20
20
 
21
21
  function Relationships(relationships) {
22
- var targetsByRelationshipId = {};
22
+ var targetsByRelationshipId = Object.create(null);
23
23
  relationships.forEach(function(relationship) {
24
24
  targetsByRelationshipId[relationship.relationshipId] = relationship.target;
25
25
  });
26
26
 
27
- var targetsByType = {};
27
+ var targetsByType = Object.create(null);
28
28
  relationships.forEach(function(relationship) {
29
29
  if (!targetsByType[relationship.type]) {
30
30
  targetsByType[relationship.type] = [];
@@ -22,21 +22,32 @@ function Styles(paragraphStyles, characterStyles, tableStyles, numberingStyles)
22
22
  Styles.EMPTY = new Styles({}, {}, {}, {});
23
23
 
24
24
  function readStylesXml(root) {
25
- var paragraphStyles = {};
26
- var characterStyles = {};
27
- var tableStyles = {};
28
- var numberingStyles = {};
29
-
30
- var styles = {
31
- "paragraph": paragraphStyles,
32
- "character": characterStyles,
33
- "table": tableStyles,
34
- "numbering": numberingStyles
35
- };
25
+ var paragraphStyles = Object.create(null);
26
+ var characterStyles = Object.create(null);
27
+ var tableStyles = Object.create(null);
28
+ var numberingStyles = Object.create(null);
36
29
 
37
30
  root.getElementsByTagName("w:style").forEach(function(styleElement) {
38
31
  var style = readStyleElement(styleElement);
39
- var styleSet = styles[style.type];
32
+ var styleSet;
33
+
34
+ switch (style.type) {
35
+ case "paragraph":
36
+ styleSet = paragraphStyles;
37
+ break;
38
+
39
+ case "character":
40
+ styleSet = characterStyles;
41
+ break;
42
+
43
+ case "table":
44
+ styleSet = tableStyles;
45
+ break;
46
+
47
+ case "numbering":
48
+ styleSet = numberingStyles;
49
+ break;
50
+ }
40
51
 
41
52
  // Per 17.7.4.17 style (Style Definition) of ECMA-376 4th edition Part 1:
42
53
  //
@@ -257,7 +257,7 @@ function htmlPathRule() {
257
257
  capture(freshRule),
258
258
  capture(separatorRule)
259
259
  ).map(function(tagName, attributesList, fresh, separator) {
260
- var attributes = {};
260
+ var attributes = Object.create(null);
261
261
  var options = {};
262
262
  attributesList.forEach(function(attribute) {
263
263
  if (attribute.append && attributes[attribute.name]) {
@@ -38,7 +38,7 @@ function element(tagName, attributes, options) {
38
38
  }
39
39
 
40
40
  function Element(tagName, attributes, options) {
41
- var tagNames = {};
41
+ var tagNames = Object.create(null);
42
42
  if (_.isArray(tagName)) {
43
43
  tagName.forEach(function(tagName) {
44
44
  tagNames[tagName] = true;
@@ -47,7 +47,7 @@ function Element(tagName, attributes, options) {
47
47
  } else {
48
48
  tagNames[tagName] = true;
49
49
  }
50
-
50
+
51
51
  this.tagName = tagName;
52
52
  this.tagNames = tagNames;
53
53
  this.attributes = attributes || {};
@@ -3,7 +3,7 @@ var RegexTokeniser = lop.RegexTokeniser;
3
3
 
4
4
  exports.tokenise = tokenise;
5
5
 
6
- var stringPrefix = "'((?:\\\\.|[^'])*)";
6
+ var stringPrefix = "'((?:\\\\(?:.|$)|[^'\\\\])*)";
7
7
 
8
8
  function tokenise(string) {
9
9
  var identifierCharacter = "(?:[a-zA-Z\\-_]|\\\\.)";
package/lib/xml/reader.js CHANGED
@@ -42,7 +42,7 @@ function readString(xmlString, namespaceMap) {
42
42
  }
43
43
  });
44
44
 
45
- var convertedAttributes = {};
45
+ var convertedAttributes = Object.create(null);
46
46
  _.forEach(element.attributes, function(attribute) {
47
47
  convertedAttributes[convertName(attribute)] = attribute.value;
48
48
  });
@@ -25,7 +25,7 @@
25
25
  // Module: lop@0.4.2
26
26
  // License: BSD-2-Clause
27
27
  //
28
- // Module: mammoth@1.12.1
28
+ // Module: mammoth@1.12.3
29
29
  // License: BSD-2-Clause
30
30
  //
31
31
  // Module: option@0.2.4
@@ -115,7 +115,7 @@ function DocumentConversion(options, comments) {
115
115
  function convertToHtml(document) {
116
116
  var messages = [];
117
117
 
118
- var html = elementToHtml(document, messages, {});
118
+ var html = elementToHtml(document, messages, Object.create(null));
119
119
 
120
120
  var deferredNodes = [];
121
121
  walkHtml(html, function(node) {
@@ -123,7 +123,7 @@ function DocumentConversion(options, comments) {
123
123
  deferredNodes.push(node);
124
124
  }
125
125
  });
126
- var deferredValues = {};
126
+ var deferredValues = Object.create(null);
127
127
  return promises.mapSeries(deferredNodes, function(deferred) {
128
128
  return deferred.value().then(function(value) {
129
129
  deferredValues[deferred.id] = value;
@@ -971,6 +971,12 @@ function BodyReader(options) {
971
971
  complexFieldStack.push({type: "begin", fldChar: element});
972
972
  currentInstrText = [];
973
973
  } else if (type === "end") {
974
+ if (complexFieldStack.length === 0) {
975
+ return emptyResultWithMessages([warning(
976
+ "Ignoring complex field end character without corresponding start character"
977
+ )]);
978
+ }
979
+
974
980
  var complexFieldEnd = complexFieldStack.pop();
975
981
  if (complexFieldEnd.type === "begin") {
976
982
  complexFieldEnd = parseCurrentInstrText(complexFieldEnd);
@@ -981,6 +987,12 @@ function BodyReader(options) {
981
987
  }));
982
988
  }
983
989
  } else if (type === "separate") {
990
+ if (complexFieldStack.length === 0) {
991
+ return emptyResultWithMessages([warning(
992
+ "Ignoring complex field separator character without corresponding start character"
993
+ )]);
994
+ }
995
+
984
996
  var complexFieldSeparate = complexFieldStack.pop();
985
997
  var complexField = parseCurrentInstrText(complexFieldSeparate);
986
998
  complexFieldStack.push(complexField);
@@ -1649,9 +1661,9 @@ exports.defaultContentTypes = contentTypes({}, {});
1649
1661
 
1650
1662
 
1651
1663
  function readContentTypesFromXml(element) {
1652
- var extensionDefaults = {};
1653
- var overrides = {};
1654
-
1664
+ var extensionDefaults = Object.create(null);
1665
+ var overrides = Object.create(null);
1666
+
1655
1667
  element.children.forEach(function(child) {
1656
1668
  if (child.name === "content-types:Default") {
1657
1669
  extensionDefaults[child.attributes.Extension] = child.attributes.ContentType;
@@ -1676,7 +1688,7 @@ function contentTypes(overrides, extensionDefaults) {
1676
1688
  } else {
1677
1689
  var pathParts = path.split(".");
1678
1690
  var extension = pathParts[pathParts.length - 1];
1679
- if (extensionDefaults.hasOwnProperty(extension)) {
1691
+ if (Object.prototype.hasOwnProperty.call(extensionDefaults, extension)) {
1680
1692
  return extensionDefaults[extension];
1681
1693
  } else {
1682
1694
  var fallback = fallbackContentTypes[extension.toLowerCase()];
@@ -1689,7 +1701,7 @@ function contentTypes(overrides, extensionDefaults) {
1689
1701
  }
1690
1702
  }
1691
1703
  };
1692
-
1704
+
1693
1705
  }
1694
1706
 
1695
1707
  },{}],8:[function(require,module,exports){
@@ -2002,7 +2014,7 @@ function Numbering(nums, abstractNums, styles) {
2002
2014
  );
2003
2015
 
2004
2016
  function findLevel(numId, level) {
2005
- return findLevelWithSeenNumIds(numId, level, {});
2017
+ return findLevelWithSeenNumIds(numId, level, Object.create(null));
2006
2018
  }
2007
2019
 
2008
2020
  function findLevelWithSeenNumIds(numId, level, seenNumIds) {
@@ -2048,7 +2060,7 @@ function readNumberingXml(root, options) {
2048
2060
  }
2049
2061
 
2050
2062
  function readAbstractNums(root) {
2051
- var abstractNums = {};
2063
+ var abstractNums = Object.create(null);
2052
2064
  root.getElementsByTagName("w:abstractNum").forEach(function(element) {
2053
2065
  var id = element.attributes["w:abstractNumId"];
2054
2066
  abstractNums[id] = readAbstractNum(element);
@@ -2057,7 +2069,7 @@ function readAbstractNums(root) {
2057
2069
  }
2058
2070
 
2059
2071
  function readAbstractNum(element) {
2060
- var levels = {};
2072
+ var levels = Object.create(null);
2061
2073
 
2062
2074
  // Some malformed documents define numbering levels without an index, and
2063
2075
  // reference the numbering using a w:numPr element without a w:ilvl child.
@@ -2095,7 +2107,7 @@ function readAbstractNum(element) {
2095
2107
  }
2096
2108
 
2097
2109
  function readNums(root) {
2098
- var nums = {};
2110
+ var nums = Object.create(null);
2099
2111
  root.getElementsByTagName("w:num").forEach(function(element) {
2100
2112
  var numId = element.attributes["w:numId"];
2101
2113
  var abstractNumId = element.first("w:abstractNumId").attributes["w:val"];
@@ -2201,12 +2213,12 @@ function readRelationships(element) {
2201
2213
  }
2202
2214
 
2203
2215
  function Relationships(relationships) {
2204
- var targetsByRelationshipId = {};
2216
+ var targetsByRelationshipId = Object.create(null);
2205
2217
  relationships.forEach(function(relationship) {
2206
2218
  targetsByRelationshipId[relationship.relationshipId] = relationship.target;
2207
2219
  });
2208
2220
 
2209
- var targetsByType = {};
2221
+ var targetsByType = Object.create(null);
2210
2222
  relationships.forEach(function(relationship) {
2211
2223
  if (!targetsByType[relationship.type]) {
2212
2224
  targetsByType[relationship.type] = [];
@@ -2326,21 +2338,32 @@ function Styles(paragraphStyles, characterStyles, tableStyles, numberingStyles)
2326
2338
  Styles.EMPTY = new Styles({}, {}, {}, {});
2327
2339
 
2328
2340
  function readStylesXml(root) {
2329
- var paragraphStyles = {};
2330
- var characterStyles = {};
2331
- var tableStyles = {};
2332
- var numberingStyles = {};
2333
-
2334
- var styles = {
2335
- "paragraph": paragraphStyles,
2336
- "character": characterStyles,
2337
- "table": tableStyles,
2338
- "numbering": numberingStyles
2339
- };
2341
+ var paragraphStyles = Object.create(null);
2342
+ var characterStyles = Object.create(null);
2343
+ var tableStyles = Object.create(null);
2344
+ var numberingStyles = Object.create(null);
2340
2345
 
2341
2346
  root.getElementsByTagName("w:style").forEach(function(styleElement) {
2342
2347
  var style = readStyleElement(styleElement);
2343
- var styleSet = styles[style.type];
2348
+ var styleSet;
2349
+
2350
+ switch (style.type) {
2351
+ case "paragraph":
2352
+ styleSet = paragraphStyles;
2353
+ break;
2354
+
2355
+ case "character":
2356
+ styleSet = characterStyles;
2357
+ break;
2358
+
2359
+ case "table":
2360
+ styleSet = tableStyles;
2361
+ break;
2362
+
2363
+ case "numbering":
2364
+ styleSet = numberingStyles;
2365
+ break;
2366
+ }
2344
2367
 
2345
2368
  // Per 17.7.4.17 style (Style Definition) of ECMA-376 4th edition Part 1:
2346
2369
  //
@@ -3259,7 +3282,7 @@ function htmlPathRule() {
3259
3282
  capture(freshRule),
3260
3283
  capture(separatorRule)
3261
3284
  ).map(function(tagName, attributesList, fresh, separator) {
3262
- var attributes = {};
3285
+ var attributes = Object.create(null);
3263
3286
  var options = {};
3264
3287
  attributesList.forEach(function(attribute) {
3265
3288
  if (attribute.append && attributes[attribute.name]) {
@@ -3509,7 +3532,7 @@ function element(tagName, attributes, options) {
3509
3532
  }
3510
3533
 
3511
3534
  function Element(tagName, attributes, options) {
3512
- var tagNames = {};
3535
+ var tagNames = Object.create(null);
3513
3536
  if (_.isArray(tagName)) {
3514
3537
  tagName.forEach(function(tagName) {
3515
3538
  tagNames[tagName] = true;
@@ -3518,7 +3541,7 @@ function Element(tagName, attributes, options) {
3518
3541
  } else {
3519
3542
  tagNames[tagName] = true;
3520
3543
  }
3521
-
3544
+
3522
3545
  this.tagName = tagName;
3523
3546
  this.tagNames = tagNames;
3524
3547
  this.attributes = attributes || {};
@@ -3551,7 +3574,7 @@ var RegexTokeniser = lop.RegexTokeniser;
3551
3574
 
3552
3575
  exports.tokenise = tokenise;
3553
3576
 
3554
- var stringPrefix = "'((?:\\\\.|[^'])*)";
3577
+ var stringPrefix = "'((?:\\\\(?:.|$)|[^'\\\\])*)";
3555
3578
 
3556
3579
  function tokenise(string) {
3557
3580
  var identifierCharacter = "(?:[a-zA-Z\\-_]|\\\\.)";
@@ -4123,7 +4146,7 @@ function readString(xmlString, namespaceMap) {
4123
4146
  }
4124
4147
  });
4125
4148
 
4126
- var convertedAttributes = {};
4149
+ var convertedAttributes = Object.create(null);
4127
4150
  _.forEach(element.attributes, function(attribute) {
4128
4151
  convertedAttributes[convertName(attribute)] = attribute.value;
4129
4152
  });