@depup/mammoth 1.12.0-depup.54 → 1.12.2-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,17 @@
1
+ # 1.12.2
2
+
3
+ * Avoid prototype pollution when reading the styles defined in a document. This
4
+ avoids an issue where a maliciously crafted document could be used to set
5
+ externalFileAccess to true.
6
+
7
+ # 1.12.1
8
+
9
+ * Fix: on Windows, when an image's content type includes a backslash in the
10
+ subpart, files may be written outside of the directory set by --output-dir.
11
+
12
+ * Detect and ignore numbering levels that use numStyleLink to refer to
13
+ themselves.
14
+
1
15
  # 1.12.0
2
16
 
3
17
  * Handle hyperlinked wp:anchor and wp:inline elements.
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.0 |
17
- | Processed | 2026-07-21 |
16
+ | Original | [mammoth](https://www.npmjs.com/package/mammoth) @ 1.12.2 |
17
+ | Processed | 2026-08-28 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 7 |
20
20
 
@@ -22,8 +22,8 @@ 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.1 |
27
27
  | bluebird | ~3.4.0 | ^3.7.2 |
28
28
  | jszip | ^3.7.1 | ^3.10.1 |
29
29
  | path-is-absolute | ^1.0.0 | ^2.0.0 |
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.1"
10
10
  },
11
11
  "bluebird": {
12
12
  "from": "~3.4.0",
@@ -29,6 +29,6 @@
29
29
  "to": "^15.1.1"
30
30
  }
31
31
  },
32
- "timestamp": "2026-07-21T17:17:25.871Z",
32
+ "timestamp": "2026-08-28T20:02:44.372Z",
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;
@@ -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,20 +17,29 @@ function Numbering(nums, abstractNums, styles) {
17
17
  );
18
18
 
19
19
  function findLevel(numId, level) {
20
+ return findLevelWithSeenNumIds(numId, level, Object.create(null));
21
+ }
22
+
23
+ function findLevelWithSeenNumIds(numId, level, seenNumIds) {
24
+ if (seenNumIds[numId]) {
25
+ return null;
26
+ }
27
+ seenNumIds[numId] = true;
28
+
20
29
  var num = nums[numId];
21
- if (num) {
22
- var abstractNum = abstractNums[num.abstractNumId];
23
- if (!abstractNum) {
24
- return null;
25
- } else if (abstractNum.numStyleLink == null) {
26
- return abstractNums[num.abstractNumId].levels[level];
27
- } else {
28
- var style = styles.findNumberingStyleById(abstractNum.numStyleLink);
29
- return findLevel(style.numId, level);
30
- }
31
- } else {
30
+ if (!num) {
32
31
  return null;
33
32
  }
33
+
34
+ var abstractNum = abstractNums[num.abstractNumId];
35
+ if (!abstractNum) {
36
+ return null;
37
+ } else if (abstractNum.numStyleLink == null) {
38
+ return abstractNums[num.abstractNumId].levels[level];
39
+ } else {
40
+ var style = styles.findNumberingStyleById(abstractNum.numStyleLink);
41
+ return findLevelWithSeenNumIds(style.numId, level, seenNumIds);
42
+ }
34
43
  }
35
44
 
36
45
  function findLevelByParagraphStyleId(styleId) {
@@ -54,7 +63,7 @@ function readNumberingXml(root, options) {
54
63
  }
55
64
 
56
65
  function readAbstractNums(root) {
57
- var abstractNums = {};
66
+ var abstractNums = Object.create(null);
58
67
  root.getElementsByTagName("w:abstractNum").forEach(function(element) {
59
68
  var id = element.attributes["w:abstractNumId"];
60
69
  abstractNums[id] = readAbstractNum(element);
@@ -63,7 +72,7 @@ function readAbstractNums(root) {
63
72
  }
64
73
 
65
74
  function readAbstractNum(element) {
66
- var levels = {};
75
+ var levels = Object.create(null);
67
76
 
68
77
  // Some malformed documents define numbering levels without an index, and
69
78
  // reference the numbering using a w:numPr element without a w:ilvl child.
@@ -101,7 +110,7 @@ function readAbstractNum(element) {
101
110
  }
102
111
 
103
112
  function readNums(root) {
104
- var nums = {};
113
+ var nums = Object.create(null);
105
114
  root.getElementsByTagName("w:num").forEach(function(element) {
106
115
  var numId = element.attributes["w:numId"];
107
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
  //
package/lib/images.js CHANGED
@@ -29,3 +29,9 @@ exports.dataUri = imgElement(function(element) {
29
29
  };
30
30
  });
31
31
  });
32
+
33
+ function imageFilenameExtension(image) {
34
+ return image.contentType.split(/\/|\\/)[1];
35
+ }
36
+
37
+ exports.imageFilenameExtension = imageFilenameExtension;
package/lib/main.js CHANGED
@@ -13,22 +13,22 @@ function main(argv) {
13
13
  var outputDir = argv.output_dir;
14
14
  var outputFormat = argv.output_format;
15
15
  var styleMapPath = argv.style_map;
16
-
16
+
17
17
  readStyleMap(styleMapPath).then(function(styleMap) {
18
18
  var options = {
19
19
  styleMap: styleMap,
20
20
  outputFormat: outputFormat
21
21
  };
22
-
22
+
23
23
  if (outputDir) {
24
24
  var basename = path.basename(docxPath, ".docx");
25
25
  outputPath = path.join(outputDir, basename + ".html");
26
26
  var imageIndex = 0;
27
27
  options.convertImage = images.imgElement(function(element) {
28
28
  imageIndex++;
29
- var extension = element.contentType.split("/")[1];
30
- var filename = imageIndex + "." + extension;
31
-
29
+ var extension = images.imageFilenameExtension(element);
30
+ var filename = imageIndex + (extension === undefined ? "" : "." + extension);
31
+
32
32
  return element.read().then(function(imageBuffer) {
33
33
  var imagePath = path.join(outputDir, filename);
34
34
  return promises.nfcall(fs.writeFile, imagePath, imageBuffer);
@@ -37,16 +37,16 @@ function main(argv) {
37
37
  });
38
38
  });
39
39
  }
40
-
40
+
41
41
  return mammoth.convert({path: docxPath}, options)
42
42
  .then(function(result) {
43
43
  result.messages.forEach(function(message) {
44
44
  process.stderr.write(message.message);
45
45
  process.stderr.write("\n");
46
46
  });
47
-
47
+
48
48
  var outputStream = outputPath ? fs.createWriteStream(outputPath) : process.stdout;
49
-
49
+
50
50
  outputStream.write(result.value);
51
51
  });
52
52
  }).done();
@@ -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 || {};
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.0
28
+ // Module: mammoth@1.12.2
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;
@@ -1649,9 +1649,9 @@ exports.defaultContentTypes = contentTypes({}, {});
1649
1649
 
1650
1650
 
1651
1651
  function readContentTypesFromXml(element) {
1652
- var extensionDefaults = {};
1653
- var overrides = {};
1654
-
1652
+ var extensionDefaults = Object.create(null);
1653
+ var overrides = Object.create(null);
1654
+
1655
1655
  element.children.forEach(function(child) {
1656
1656
  if (child.name === "content-types:Default") {
1657
1657
  extensionDefaults[child.attributes.Extension] = child.attributes.ContentType;
@@ -1676,7 +1676,7 @@ function contentTypes(overrides, extensionDefaults) {
1676
1676
  } else {
1677
1677
  var pathParts = path.split(".");
1678
1678
  var extension = pathParts[pathParts.length - 1];
1679
- if (extensionDefaults.hasOwnProperty(extension)) {
1679
+ if (Object.prototype.hasOwnProperty.call(extensionDefaults, extension)) {
1680
1680
  return extensionDefaults[extension];
1681
1681
  } else {
1682
1682
  var fallback = fallbackContentTypes[extension.toLowerCase()];
@@ -1689,7 +1689,7 @@ function contentTypes(overrides, extensionDefaults) {
1689
1689
  }
1690
1690
  }
1691
1691
  };
1692
-
1692
+
1693
1693
  }
1694
1694
 
1695
1695
  },{}],8:[function(require,module,exports){
@@ -2002,19 +2002,28 @@ function Numbering(nums, abstractNums, styles) {
2002
2002
  );
2003
2003
 
2004
2004
  function findLevel(numId, level) {
2005
+ return findLevelWithSeenNumIds(numId, level, Object.create(null));
2006
+ }
2007
+
2008
+ function findLevelWithSeenNumIds(numId, level, seenNumIds) {
2009
+ if (seenNumIds[numId]) {
2010
+ return null;
2011
+ }
2012
+ seenNumIds[numId] = true;
2013
+
2005
2014
  var num = nums[numId];
2006
- if (num) {
2007
- var abstractNum = abstractNums[num.abstractNumId];
2008
- if (!abstractNum) {
2009
- return null;
2010
- } else if (abstractNum.numStyleLink == null) {
2011
- return abstractNums[num.abstractNumId].levels[level];
2012
- } else {
2013
- var style = styles.findNumberingStyleById(abstractNum.numStyleLink);
2014
- return findLevel(style.numId, level);
2015
- }
2016
- } else {
2015
+ if (!num) {
2016
+ return null;
2017
+ }
2018
+
2019
+ var abstractNum = abstractNums[num.abstractNumId];
2020
+ if (!abstractNum) {
2017
2021
  return null;
2022
+ } else if (abstractNum.numStyleLink == null) {
2023
+ return abstractNums[num.abstractNumId].levels[level];
2024
+ } else {
2025
+ var style = styles.findNumberingStyleById(abstractNum.numStyleLink);
2026
+ return findLevelWithSeenNumIds(style.numId, level, seenNumIds);
2018
2027
  }
2019
2028
  }
2020
2029
 
@@ -2039,7 +2048,7 @@ function readNumberingXml(root, options) {
2039
2048
  }
2040
2049
 
2041
2050
  function readAbstractNums(root) {
2042
- var abstractNums = {};
2051
+ var abstractNums = Object.create(null);
2043
2052
  root.getElementsByTagName("w:abstractNum").forEach(function(element) {
2044
2053
  var id = element.attributes["w:abstractNumId"];
2045
2054
  abstractNums[id] = readAbstractNum(element);
@@ -2048,7 +2057,7 @@ function readAbstractNums(root) {
2048
2057
  }
2049
2058
 
2050
2059
  function readAbstractNum(element) {
2051
- var levels = {};
2060
+ var levels = Object.create(null);
2052
2061
 
2053
2062
  // Some malformed documents define numbering levels without an index, and
2054
2063
  // reference the numbering using a w:numPr element without a w:ilvl child.
@@ -2086,7 +2095,7 @@ function readAbstractNum(element) {
2086
2095
  }
2087
2096
 
2088
2097
  function readNums(root) {
2089
- var nums = {};
2098
+ var nums = Object.create(null);
2090
2099
  root.getElementsByTagName("w:num").forEach(function(element) {
2091
2100
  var numId = element.attributes["w:numId"];
2092
2101
  var abstractNumId = element.first("w:abstractNumId").attributes["w:val"];
@@ -2192,12 +2201,12 @@ function readRelationships(element) {
2192
2201
  }
2193
2202
 
2194
2203
  function Relationships(relationships) {
2195
- var targetsByRelationshipId = {};
2204
+ var targetsByRelationshipId = Object.create(null);
2196
2205
  relationships.forEach(function(relationship) {
2197
2206
  targetsByRelationshipId[relationship.relationshipId] = relationship.target;
2198
2207
  });
2199
2208
 
2200
- var targetsByType = {};
2209
+ var targetsByType = Object.create(null);
2201
2210
  relationships.forEach(function(relationship) {
2202
2211
  if (!targetsByType[relationship.type]) {
2203
2212
  targetsByType[relationship.type] = [];
@@ -2317,21 +2326,32 @@ function Styles(paragraphStyles, characterStyles, tableStyles, numberingStyles)
2317
2326
  Styles.EMPTY = new Styles({}, {}, {}, {});
2318
2327
 
2319
2328
  function readStylesXml(root) {
2320
- var paragraphStyles = {};
2321
- var characterStyles = {};
2322
- var tableStyles = {};
2323
- var numberingStyles = {};
2324
-
2325
- var styles = {
2326
- "paragraph": paragraphStyles,
2327
- "character": characterStyles,
2328
- "table": tableStyles,
2329
- "numbering": numberingStyles
2330
- };
2329
+ var paragraphStyles = Object.create(null);
2330
+ var characterStyles = Object.create(null);
2331
+ var tableStyles = Object.create(null);
2332
+ var numberingStyles = Object.create(null);
2331
2333
 
2332
2334
  root.getElementsByTagName("w:style").forEach(function(styleElement) {
2333
2335
  var style = readStyleElement(styleElement);
2334
- var styleSet = styles[style.type];
2336
+ var styleSet;
2337
+
2338
+ switch (style.type) {
2339
+ case "paragraph":
2340
+ styleSet = paragraphStyles;
2341
+ break;
2342
+
2343
+ case "character":
2344
+ styleSet = characterStyles;
2345
+ break;
2346
+
2347
+ case "table":
2348
+ styleSet = tableStyles;
2349
+ break;
2350
+
2351
+ case "numbering":
2352
+ styleSet = numberingStyles;
2353
+ break;
2354
+ }
2335
2355
 
2336
2356
  // Per 17.7.4.17 style (Style Definition) of ECMA-376 4th edition Part 1:
2337
2357
  //
@@ -2626,6 +2646,12 @@ exports.dataUri = imgElement(function(element) {
2626
2646
  });
2627
2647
  });
2628
2648
 
2649
+ function imageFilenameExtension(image) {
2650
+ return image.contentType.split(/\/|\\/)[1];
2651
+ }
2652
+
2653
+ exports.imageFilenameExtension = imageFilenameExtension;
2654
+
2629
2655
  },{"./html":18,"./promises":23,"underscore":102}],21:[function(require,module,exports){
2630
2656
  (function (Buffer){
2631
2657
  var _ = require("underscore");
@@ -3244,7 +3270,7 @@ function htmlPathRule() {
3244
3270
  capture(freshRule),
3245
3271
  capture(separatorRule)
3246
3272
  ).map(function(tagName, attributesList, fresh, separator) {
3247
- var attributes = {};
3273
+ var attributes = Object.create(null);
3248
3274
  var options = {};
3249
3275
  attributesList.forEach(function(attribute) {
3250
3276
  if (attribute.append && attributes[attribute.name]) {
@@ -3494,7 +3520,7 @@ function element(tagName, attributes, options) {
3494
3520
  }
3495
3521
 
3496
3522
  function Element(tagName, attributes, options) {
3497
- var tagNames = {};
3523
+ var tagNames = Object.create(null);
3498
3524
  if (_.isArray(tagName)) {
3499
3525
  tagName.forEach(function(tagName) {
3500
3526
  tagNames[tagName] = true;
@@ -3503,7 +3529,7 @@ function Element(tagName, attributes, options) {
3503
3529
  } else {
3504
3530
  tagNames[tagName] = true;
3505
3531
  }
3506
-
3532
+
3507
3533
  this.tagName = tagName;
3508
3534
  this.tagNames = tagNames;
3509
3535
  this.attributes = attributes || {};
@@ -4108,7 +4134,7 @@ function readString(xmlString, namespaceMap) {
4108
4134
  }
4109
4135
  });
4110
4136
 
4111
- var convertedAttributes = {};
4137
+ var convertedAttributes = Object.create(null);
4112
4138
  _.forEach(element.attributes, function(attribute) {
4113
4139
  convertedAttributes[convertName(attribute)] = attribute.value;
4114
4140
  });