@zowe/db2-for-zowe-cli 6.1.18 → 6.1.19

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.
Files changed (76) hide show
  1. package/node_modules/adm-zip/adm-zip.js +32 -6
  2. package/node_modules/adm-zip/headers/entryHeader.js +13 -1
  3. package/node_modules/adm-zip/methods/inflater.js +33 -3
  4. package/node_modules/adm-zip/package.json +2 -2
  5. package/node_modules/adm-zip/util/errors.js +3 -0
  6. package/node_modules/adm-zip/util/utils.js +102 -14
  7. package/node_modules/adm-zip/zipEntry.js +43 -18
  8. package/node_modules/adm-zip/zipFile.js +10 -0
  9. package/node_modules/axios/README.md +41 -106
  10. package/node_modules/axios/dist/axios.js +931 -278
  11. package/node_modules/axios/dist/axios.min.js +2 -2
  12. package/node_modules/axios/dist/axios.min.js.map +1 -1
  13. package/node_modules/axios/dist/browser/axios.cjs +948 -268
  14. package/node_modules/axios/dist/esm/axios.js +948 -268
  15. package/node_modules/axios/dist/esm/axios.min.js +2 -2
  16. package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
  17. package/node_modules/axios/dist/node/axios.cjs +925 -242
  18. package/node_modules/axios/index.d.cts +20 -1
  19. package/node_modules/axios/index.d.ts +18 -1
  20. package/node_modules/axios/lib/adapters/fetch.js +73 -20
  21. package/node_modules/axios/lib/adapters/http.js +145 -26
  22. package/node_modules/axios/lib/adapters/xhr.js +120 -13
  23. package/node_modules/axios/lib/core/Axios.js +67 -12
  24. package/node_modules/axios/lib/core/AxiosError.js +59 -0
  25. package/node_modules/axios/lib/core/AxiosHeaders.js +17 -4
  26. package/node_modules/axios/lib/core/InterceptorManager.js +13 -2
  27. package/node_modules/axios/lib/core/assertParamsAcyclic.js +49 -0
  28. package/node_modules/axios/lib/core/createMultipartBody.js +37 -0
  29. package/node_modules/axios/lib/core/dispatchRequest.js +20 -0
  30. package/node_modules/axios/lib/core/mergeConfig.js +183 -120
  31. package/node_modules/axios/lib/defaults/transitional.js +1 -0
  32. package/node_modules/axios/lib/env/data.js +1 -1
  33. package/node_modules/axios/lib/helpers/AxiosTransformStream.js +11 -2
  34. package/node_modules/axios/lib/helpers/Http2Sessions.js +2 -1
  35. package/node_modules/axios/lib/helpers/composeSignals.js +6 -3
  36. package/node_modules/axios/lib/helpers/cookies.js +30 -6
  37. package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +34 -7
  38. package/node_modules/axios/lib/helpers/formDataToBlob.js +113 -0
  39. package/node_modules/axios/lib/helpers/formDataToJSON.js +25 -1
  40. package/node_modules/axios/lib/helpers/fromDataURI.js +8 -2
  41. package/node_modules/axios/lib/helpers/isURLSameOrigin.js +4 -9
  42. package/node_modules/axios/lib/helpers/parseHeaders.js +2 -1
  43. package/node_modules/axios/lib/helpers/parseProtocol.js +1 -1
  44. package/node_modules/axios/lib/helpers/resolveConfig.js +16 -3
  45. package/node_modules/axios/lib/helpers/shouldBypassProxy.js +16 -1
  46. package/node_modules/axios/lib/utils.js +61 -10
  47. package/node_modules/axios/package.json +1 -2
  48. package/node_modules/follow-redirects/README.md +27 -1
  49. package/node_modules/follow-redirects/index.js +11 -6
  50. package/node_modules/follow-redirects/package.json +1 -1
  51. package/node_modules/fs-extra/README.md +0 -1
  52. package/node_modules/fs-extra/lib/empty/index.js +4 -2
  53. package/node_modules/fs-extra/lib/util/stat.js +12 -2
  54. package/node_modules/fs-extra/package.json +1 -1
  55. package/node_modules/string_decoder/node_modules/safe-buffer/LICENSE +21 -0
  56. package/node_modules/string_decoder/node_modules/safe-buffer/README.md +584 -0
  57. package/node_modules/string_decoder/node_modules/safe-buffer/index.d.ts +187 -0
  58. package/node_modules/string_decoder/node_modules/safe-buffer/index.js +62 -0
  59. package/node_modules/string_decoder/node_modules/safe-buffer/package.json +37 -0
  60. package/node_modules/which-typed-array/CHANGELOG.md +14 -0
  61. package/node_modules/which-typed-array/README.md +0 -2
  62. package/node_modules/which-typed-array/index.d.ts +288 -11
  63. package/node_modules/which-typed-array/index.js +6 -7
  64. package/node_modules/which-typed-array/package.json +12 -11
  65. package/package.json +1 -6
  66. package/node_modules/which-typed-array/eslint.config.mjs +0 -12
  67. package/node_modules/which-typed-array/test/index.js +0 -105
  68. /package/node_modules/{tar-fs/node_modules/chownr → chownr}/LICENSE +0 -0
  69. /package/node_modules/{tar-fs/node_modules/chownr → chownr}/README.md +0 -0
  70. /package/node_modules/{tar-fs/node_modules/chownr → chownr}/chownr.js +0 -0
  71. /package/node_modules/{tar-fs/node_modules/chownr → chownr}/package.json +0 -0
  72. /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/.travis.yml +0 -0
  73. /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/LICENSE +0 -0
  74. /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/README.md +0 -0
  75. /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/lib/string_decoder.js +0 -0
  76. /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/package.json +0 -0
@@ -498,7 +498,11 @@ module.exports = function (/**String*/ input, /** object */ options) {
498
498
  addLocalFolderAsync2: function (options, callback) {
499
499
  const self = this;
500
500
  options = typeof options === "object" ? options : { localPath: options };
501
- const localPath = pth.resolve(fixPath(options.localPath));
501
+ // Resolve the local filesystem path with the platform resolver. Do NOT
502
+ // run it through fixPath: that normalizes ZIP-internal paths to POSIX
503
+ // and prepends "/", which turns a Windows path like C:\dir into
504
+ // \C:\dir, so readdir finds nothing and the archive comes out empty.
505
+ const localPath = pth.resolve(options.localPath);
502
506
  let { zipPath, filter, namefix } = options;
503
507
 
504
508
  if (filter instanceof RegExp) {
@@ -533,14 +537,21 @@ module.exports = function (/**String*/ input, /** object */ options) {
533
537
 
534
538
  filetools.fs.open(localPath, "r", function (err) {
535
539
  if (err && err.code === "ENOENT") {
536
- callback(undefined, Utils.Errors.FILE_NOT_FOUND(localPath));
540
+ // callback is (err, done); errors belong in the first argument,
541
+ // otherwise addLocalFolderPromise treats the error as "done" and
542
+ // resolves instead of rejecting.
543
+ callback(Utils.Errors.FILE_NOT_FOUND(localPath), false);
537
544
  } else if (err) {
538
- callback(undefined, err);
545
+ callback(err, false);
539
546
  } else {
540
547
  filetools.findFilesAsync(localPath, function (err, fileEntries) {
541
- if (err) return callback(err);
548
+ if (err) return callback(err, false);
542
549
  fileEntries = fileEntries.filter((dir) => filter(relPathFix(dir)));
543
- if (!fileEntries.length) callback(undefined, false);
550
+ // Nothing to add (empty folder or everything filtered out) is a
551
+ // success, not an error. Report done and stop, otherwise the
552
+ // reduce below runs and the callback fires a second time -- and
553
+ // signalling done=false left addLocalFolderPromise hanging.
554
+ if (!fileEntries.length) return callback(undefined, true);
544
555
 
545
556
  setImmediate(
546
557
  fileEntries.reverse().reduce(function (next, entry) {
@@ -575,7 +586,7 @@ module.exports = function (/**String*/ input, /** object */ options) {
575
586
  addLocalFolderPromise: function (localPath, props) {
576
587
  return new Promise((resolve, reject) => {
577
588
  this.addLocalFolderAsync2(Object.assign({ localPath }, props), (err, done) => {
578
- if (err) reject(err);
589
+ if (err) return reject(err);
579
590
  if (done) resolve(this);
580
591
  });
581
592
  });
@@ -709,6 +720,8 @@ module.exports = function (/**String*/ input, /** object */ options) {
709
720
  // collapsed subdirectories together (issue #306).
710
721
  var name = canonical(maintainEntryPath ? child.entryName : child.entryName.substring(item.entryName.length));
711
722
  var childName = sanitize(targetPath, name);
723
+ // reject writing through a pre-existing symlink inside the target
724
+ filetools.assertPathSafe(targetPath, childName);
712
725
  // The reverse operation for attr depend on method addFile()
713
726
  const fileAttr = keepOriginalPermission ? child.header.fileAttr : undefined;
714
727
  filetools.writeFileTo(childName, content, overwrite, fileAttr);
@@ -719,6 +732,9 @@ module.exports = function (/**String*/ input, /** object */ options) {
719
732
  var content = item.getData(_zip.password);
720
733
  if (!content) throw Utils.Errors.CANT_EXTRACT_FILE();
721
734
 
735
+ // reject writing through a pre-existing symlink inside the target
736
+ filetools.assertPathSafe(targetPath, target);
737
+
722
738
  if (filetools.fs.existsSync(target) && !overwrite) {
723
739
  throw Utils.Errors.CANT_OVERRIDE();
724
740
  }
@@ -775,6 +791,8 @@ module.exports = function (/**String*/ input, /** object */ options) {
775
791
  const dirEntries = [];
776
792
  _zip.entries.forEach(function (entry) {
777
793
  var entryName = sanitize(targetPath, canonical(entry.entryName));
794
+ // reject writing through a pre-existing symlink inside the target
795
+ filetools.assertPathSafe(targetPath, entryName);
778
796
  if (entry.isDirectory) {
779
797
  filetools.makeDir(entryName);
780
798
  // defer restoring the directory permission until its files are written
@@ -854,6 +872,8 @@ module.exports = function (/**String*/ input, /** object */ options) {
854
872
  // The reverse operation for attr depend on method addFile()
855
873
  const dirAttr = keepOriginalPermission ? entry.header.fileAttr : undefined;
856
874
  try {
875
+ // reject writing through a pre-existing symlink inside the target
876
+ filetools.assertPathSafe(targetPath, dirPath);
857
877
  filetools.makeDir(dirPath);
858
878
  } catch (er) {
859
879
  callback(getError("Unable to create folder", dirPath));
@@ -890,6 +910,12 @@ module.exports = function (/**String*/ input, /** object */ options) {
890
910
  } else {
891
911
  const entryName = pth.normalize(canonical(entry.entryName));
892
912
  const filePath = sanitize(targetPath, entryName);
913
+ try {
914
+ // reject writing through a pre-existing symlink inside the target
915
+ filetools.assertPathSafe(targetPath, filePath);
916
+ } catch (er) {
917
+ return next(er);
918
+ }
893
919
  entry.getDataAsync(function (content, err_1) {
894
920
  if (err_1) {
895
921
  next(err_1);
@@ -185,7 +185,12 @@ module.exports = function () {
185
185
 
186
186
  // get Unix file permissions
187
187
  get fileAttr() {
188
- return (_attr || 0) >> 16 & 0xfff;
188
+ // Mask to the 9 rwxrwxrwx bits only. The setuid (0o4000), setgid
189
+ // (0o2000) and sticky (0o1000) bits are attacker-controlled archive
190
+ // metadata; preserving them on extraction (keepOriginalPermission)
191
+ // lets a crafted zip plant a setuid-root binary when extracting as
192
+ // root, a local privilege escalation (GHSA-679w-jf3m-wh39).
193
+ return ((_attr || 0) >> 16) & 0o777;
189
194
  },
190
195
 
191
196
  get offset() {
@@ -212,6 +217,13 @@ module.exports = function () {
212
217
  },
213
218
 
214
219
  loadLocalHeaderFromBinary: function (/*Buffer*/ input) {
220
+ // The LOC offset comes from the central directory and is attacker
221
+ // controlled. Reject one that would read past the end of the buffer,
222
+ // otherwise readUInt32LE below throws a raw RangeError instead of a
223
+ // clean INVALID_LOC (and escapes the async error path).
224
+ if (_offset < 0 || _offset + Constants.LOCHDR > input.length) {
225
+ throw Utils.Errors.INVALID_LOC();
226
+ }
215
227
  var data = input.slice(_offset, _offset + Constants.LOCHDR);
216
228
  // 30 bytes and should start with "PK\003\004"
217
229
  if (data.readUInt32LE(0) !== Constants.LOCSIG) {
@@ -1,8 +1,15 @@
1
1
  const version = +(process?.versions?.node ?? "").split(".")[0] || 0;
2
+ const Errors = require("../util/errors");
2
3
 
3
4
  module.exports = function (/*Buffer*/ inbuf, /*number*/ expectedLength) {
4
5
  var zlib = require("zlib");
5
- const option = version >= 15 && expectedLength > 0 ? { maxOutputLength: expectedLength } : {};
6
+ // Cap decompression output at the entry's declared uncompressed size to bound
7
+ // decompression bombs (CVE-2026-39244). A declared size of 0 must not disable
8
+ // the cap: a genuinely empty entry inflates to 0 bytes, so a 1-byte floor
9
+ // still lets it through while stopping a bomb that lies about its size
10
+ // (GHSA-rcw4-f5rp-g42v). zlib requires maxOutputLength >= 1.
11
+ const maxOutputLength = expectedLength > 0 ? expectedLength : 1;
12
+ const option = version >= 15 ? { maxOutputLength } : {};
6
13
 
7
14
  return {
8
15
  inflate: function () {
@@ -12,12 +19,35 @@ module.exports = function (/*Buffer*/ inbuf, /*number*/ expectedLength) {
12
19
  inflateAsync: function (/*Function*/ callback) {
13
20
  var tmp = zlib.createInflateRaw(option),
14
21
  parts = [],
15
- total = 0;
22
+ total = 0,
23
+ done = false;
24
+ const fail = function (err) {
25
+ if (done) return;
26
+ done = true;
27
+ tmp.destroy();
28
+ callback && callback(Buffer.alloc(0), err);
29
+ };
30
+ // Route stream errors (e.g. Z_DATA_ERROR on malformed input) through the
31
+ // callback. Without an "error" listener zlib re-throws the event as an
32
+ // uncaught exception on a later tick, crashing the host process instead
33
+ // of failing the call (GHSA-8238-w5pm-2374).
34
+ tmp.on("error", function (err) {
35
+ fail(err);
36
+ });
16
37
  tmp.on("data", function (data) {
17
- parts.push(data);
38
+ if (done) return;
18
39
  total += data.length;
40
+ // The streaming API ignores maxOutputLength, so enforce the cap by
41
+ // hand; otherwise the async path decompresses without limit while the
42
+ // sync path is capped (GHSA-v429-h5qx-84wm, GHSA-c6fg-446q-cg94).
43
+ if (total > maxOutputLength) {
44
+ return fail(Errors.MAX_OUTPUT_EXCEEDED());
45
+ }
46
+ parts.push(data);
19
47
  });
20
48
  tmp.on("end", function () {
49
+ if (done) return;
50
+ done = true;
21
51
  var buf = Buffer.alloc(total),
22
52
  written = 0;
23
53
  buf.fill(0);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adm-zip",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Javascript implementation of zip for nodejs with support for electron original-fs. Allows user to create or extract zip files both in memory or to/from disk",
5
5
  "scripts": {
6
6
  "test": "mocha -R spec",
@@ -49,7 +49,7 @@
49
49
  "devDependencies": {
50
50
  "chai": "^6.2.2",
51
51
  "iconv-lite": "^0.7.2",
52
- "mocha": "12.0.0-beta-10",
52
+ "mocha": "^12.0.0",
53
53
  "prettier": "^3.8.1",
54
54
  "rimraf": "^3.0.2"
55
55
  }
@@ -12,6 +12,7 @@ const errors = {
12
12
  /* ZipEntry error messages*/
13
13
  NO_DATA: "Nothing to decompress",
14
14
  BAD_CRC: "CRC32 checksum failed {0}",
15
+ MAX_OUTPUT_EXCEEDED: "Decompressed data exceeds the declared uncompressed size",
15
16
  FILE_IN_THE_WAY: "There is a file in the way: {0}",
16
17
  UNKNOWN_METHOD: "Invalid/unsupported compression method",
17
18
 
@@ -33,11 +34,13 @@ const errors = {
33
34
  DISK_ENTRY_TOO_LARGE: "Number of disk entries is too large",
34
35
  NO_ZIP: "No zip file was loaded",
35
36
  NO_ENTRY: "Entry doesn't exist",
37
+ DUPLICATE_ENTRY: "Duplicate entry name {0}",
36
38
  DIRECTORY_CONTENT_ERROR: "A directory cannot have content",
37
39
  FILE_NOT_FOUND: 'File not found: "{0}"',
38
40
  NOT_IMPLEMENTED: "Not implemented",
39
41
  INVALID_FILENAME: "Invalid filename",
40
42
  INVALID_FORMAT: "Invalid or unsupported zip format. No END header found",
43
+ ZIP64_VALUE_TOO_LARGE: "Zip64 value exceeds the maximum safe integer",
41
44
  INVALID_PASS_PARAM: "Incompatible password parameter",
42
45
  WRONG_PASSWORD: "Wrong Password",
43
46
 
@@ -159,8 +159,59 @@ Utils.prototype.writeFileToAsync = function (/*String*/ path, /*Buffer*/ content
159
159
  });
160
160
  };
161
161
 
162
+ // Guard extraction against writing through a symlink that already exists inside
163
+ // the target directory. sanitize() only proves the textual path stays under the
164
+ // root; it cannot see that a component on disk is a symlink pointing elsewhere,
165
+ // so open()/mkdir() would follow it and write outside the root. Walk every path
166
+ // component strictly below root and reject any that is a symlink. Components at
167
+ // or above root are the caller's own choice and are left untouched, so a root
168
+ // that itself lives under a symlink (e.g. /tmp on macOS) still extracts.
169
+ Utils.prototype.assertPathSafe = function (/*String*/ root, /*String*/ target) {
170
+ const self = this;
171
+ if (typeof self.fs.lstatSync !== "function") return;
172
+
173
+ const resolvedRoot = pth.resolve(root);
174
+ const resolvedTarget = pth.resolve(target);
175
+ if (resolvedTarget === resolvedRoot) return;
176
+
177
+ const rel = pth.relative(resolvedRoot, resolvedTarget);
178
+ // Not under root: sanitize() is responsible for that case; nothing to walk.
179
+ if (!rel || rel === ".." || rel.startsWith(".." + pth.sep) || pth.isAbsolute(rel)) return;
180
+
181
+ let cur = resolvedRoot;
182
+ for (const part of rel.split(pth.sep)) {
183
+ if (!part || part === ".") continue;
184
+ cur = pth.join(cur, part);
185
+ let stat;
186
+ try {
187
+ stat = self.fs.lstatSync(cur);
188
+ } catch (e) {
189
+ break; // component does not exist yet: nothing below it can be a symlink
190
+ }
191
+ if (stat.isSymbolicLink()) throw Errors.FILE_IN_THE_WAY(`"${cur}"`);
192
+ }
193
+ };
194
+
162
195
  Utils.prototype.findFiles = function (/*String*/ path) {
163
196
  const self = this;
197
+ const canLstat = typeof self.fs.lstatSync === "function";
198
+ const rootReal = self.fs.realpathSync(path);
199
+
200
+ // A symlink whose target lies outside the folder being archived must not be
201
+ // followed: statSync would dereference it and copy the target's contents into
202
+ // the archive, disclosing files outside the root (GHSA-wx42-xcp7-pgr4). Allow
203
+ // symlinks that resolve to a location inside the root, reject any that escape.
204
+ function escapesRoot(/*String*/ p) {
205
+ if (!canLstat) return false;
206
+ if (!self.fs.lstatSync(p).isSymbolicLink()) return false;
207
+ let real;
208
+ try {
209
+ real = self.fs.realpathSync(p);
210
+ } catch (e) {
211
+ return true; // dangling or unresolvable symlink: do not follow
212
+ }
213
+ return !(real === rootReal || real.startsWith(rootReal + pth.sep));
214
+ }
164
215
 
165
216
  function findSync(/*String*/ dir, /*RegExp*/ pattern, /*Boolean*/ recursive, /*Set*/ visited) {
166
217
  if (typeof pattern === "boolean") {
@@ -170,6 +221,9 @@ Utils.prototype.findFiles = function (/*String*/ path) {
170
221
  let files = [];
171
222
  self.fs.readdirSync(dir).forEach(function (file) {
172
223
  const path = pth.join(dir, file);
224
+
225
+ if (escapesRoot(path)) return;
226
+
173
227
  const stat = self.fs.statSync(path);
174
228
 
175
229
  if (!pattern || pattern.test(path)) {
@@ -191,7 +245,7 @@ Utils.prototype.findFiles = function (/*String*/ path) {
191
245
  return files;
192
246
  }
193
247
 
194
- return findSync(path, undefined, true, new Set([self.fs.realpathSync(path)]));
248
+ return findSync(path, undefined, true, new Set([rootReal]));
195
249
  };
196
250
 
197
251
  /**
@@ -217,6 +271,25 @@ Utils.prototype.findFilesAsync = function (dir, cb) {
217
271
  cb(err, err ? undefined : results);
218
272
  };
219
273
 
274
+ const canLstat = typeof self.fs.lstat === "function";
275
+ let rootReal = null;
276
+
277
+ // Reject a symlink whose target escapes the root being archived, so its
278
+ // contents are not dereferenced and copied into the archive
279
+ // (GHSA-wx42-xcp7-pgr4). A symlink resolving to a location inside the root is
280
+ // allowed; a dangling or escaping one is skipped. Calls back (err, escapes).
281
+ const escapesRoot = function (file, cb) {
282
+ if (!canLstat) return cb(null, false);
283
+ self.fs.lstat(file, function (err, lst) {
284
+ if (err) return cb(err);
285
+ if (!lst || !lst.isSymbolicLink()) return cb(null, false);
286
+ self.fs.realpath(file, function (err, real) {
287
+ if (err) return cb(null, true); // dangling: do not follow
288
+ cb(null, !(real === rootReal || real.startsWith(rootReal + pth.sep)));
289
+ });
290
+ });
291
+ };
292
+
220
293
  // Descend by resolved real path and skip directories already visited, so a
221
294
  // symlink pointing back to an ancestor cannot recurse forever (issue #541).
222
295
  const walk = function (dir, visited, done) {
@@ -226,27 +299,34 @@ Utils.prototype.findFilesAsync = function (dir, cb) {
226
299
  if (!pending) return done();
227
300
  list.forEach(function (name) {
228
301
  const file = pth.join(dir, name);
229
- self.fs.stat(file, function (err, stat) {
302
+ escapesRoot(file, function (err, escapes) {
230
303
  if (err) return done(err);
231
- if (!stat) {
232
- if (!--pending) done();
233
- return;
234
- }
235
- results.push(pth.normalize(file) + (stat.isDirectory() ? self.sep : ""));
236
- if (!stat.isDirectory()) {
304
+ if (escapes) {
237
305
  if (!--pending) done();
238
306
  return;
239
307
  }
240
- self.fs.realpath(file, function (err, realDir) {
308
+ self.fs.stat(file, function (err, stat) {
241
309
  if (err) return done(err);
242
- if (visited.has(realDir)) {
310
+ if (!stat) {
243
311
  if (!--pending) done();
244
312
  return;
245
313
  }
246
- visited.add(realDir);
247
- walk(file, visited, function (err) {
248
- if (err) return done(err);
314
+ results.push(pth.normalize(file) + (stat.isDirectory() ? self.sep : ""));
315
+ if (!stat.isDirectory()) {
249
316
  if (!--pending) done();
317
+ return;
318
+ }
319
+ self.fs.realpath(file, function (err, realDir) {
320
+ if (err) return done(err);
321
+ if (visited.has(realDir)) {
322
+ if (!--pending) done();
323
+ return;
324
+ }
325
+ visited.add(realDir);
326
+ walk(file, visited, function (err) {
327
+ if (err) return done(err);
328
+ if (!--pending) done();
329
+ });
250
330
  });
251
331
  });
252
332
  });
@@ -256,6 +336,7 @@ Utils.prototype.findFilesAsync = function (dir, cb) {
256
336
 
257
337
  self.fs.realpath(dir, function (err, realDir) {
258
338
  if (err) return finish(err);
339
+ rootReal = realDir;
259
340
  walk(dir, new Set([realDir]), finish);
260
341
  });
261
342
  };
@@ -365,7 +446,14 @@ Utils.toBuffer = function toBuffer(/*buffer, Uint8Array, string*/ input, /* func
365
446
  Utils.readBigUInt64LE = function (/*Buffer*/ buffer, /*int*/ index) {
366
447
  const lo = buffer.readUInt32LE(index);
367
448
  const hi = buffer.readUInt32LE(index + 4);
368
- return hi * 0x100000000 + lo;
449
+ const value = hi * 0x100000000 + lo;
450
+ // The result is a JS number, so values above 2^53 - 1 cannot be represented
451
+ // exactly. These are zip64 sizes/offsets/counts used as buffer indices; a
452
+ // silently rounded value would misparse the archive. Reject instead.
453
+ if (value > Number.MAX_SAFE_INTEGER) {
454
+ throw Errors.ZIP64_VALUE_TOO_LARGE();
455
+ }
456
+ return value;
369
457
  };
370
458
 
371
459
  Utils.writeBigUInt64LE = function (/*Buffer*/ buffer, /*Number*/ value, /*int*/ index) {
@@ -25,7 +25,16 @@ module.exports = function (/** object */ options, /*Buffer*/ input) {
25
25
  return Buffer.alloc(0);
26
26
  }
27
27
  _extralocal = _centralHeader.loadLocalHeaderFromBinary(input);
28
- return input.slice(_centralHeader.realDataOffset, _centralHeader.realDataOffset + _centralHeader.compressedSize);
28
+ const dataOffset = _centralHeader.realDataOffset;
29
+ const dataEnd = dataOffset + _centralHeader.compressedSize;
30
+ // The offsets and sizes come from attacker-controlled headers. Require the
31
+ // declared compressed extent to be fully present rather than letting slice()
32
+ // silently clamp to a short buffer (which only surfaces later as a CRC
33
+ // failure). Fail loudly with a header error instead (GHSA-wwrv-q5gf-5843).
34
+ if (dataOffset < 0 || dataEnd < dataOffset || dataEnd > input.length) {
35
+ throw Utils.Errors.INVALID_LOC();
36
+ }
37
+ return input.slice(dataOffset, dataEnd);
29
38
  }
30
39
 
31
40
  function crc32OK(data) {
@@ -60,19 +69,32 @@ module.exports = function (/** object */ options, /*Buffer*/ input) {
60
69
  return Buffer.alloc(0);
61
70
  }
62
71
 
63
- var compressedData = getCompressedDataFromZip();
72
+ var compressedData;
73
+ try {
74
+ compressedData = getCompressedDataFromZip();
64
75
 
65
- if (compressedData.length === 0) {
66
- // File is empty, nothing to decompress.
67
- if (async && callback) callback(compressedData);
68
- return compressedData;
69
- }
76
+ if (compressedData.length === 0) {
77
+ // File is empty, nothing to decompress.
78
+ if (async && callback) callback(compressedData);
79
+ return compressedData;
80
+ }
70
81
 
71
- if (_centralHeader.encrypted) {
72
- if ("string" !== typeof pass && !Buffer.isBuffer(pass)) {
73
- throw Utils.Errors.INVALID_PASS_PARAM();
82
+ if (_centralHeader.encrypted) {
83
+ if ("string" !== typeof pass && !Buffer.isBuffer(pass)) {
84
+ throw Utils.Errors.INVALID_PASS_PARAM();
85
+ }
86
+ compressedData = Methods.ZipCrypto.decrypt(compressedData, _centralHeader, pass);
87
+ }
88
+ } catch (err) {
89
+ // These synchronous parse/setup steps run before any callback fires.
90
+ // In async mode a malformed local header (e.g. a bad LOC offset) would
91
+ // otherwise throw out of getDataAsync and bypass the callback error
92
+ // channel, crashing the caller. Route it through the callback instead.
93
+ if (async && callback) {
94
+ callback(Buffer.alloc(0), err);
95
+ return Buffer.alloc(0);
74
96
  }
75
- compressedData = Methods.ZipCrypto.decrypt(compressedData, _centralHeader, pass);
97
+ throw err;
76
98
  }
77
99
 
78
100
  var data;
@@ -107,13 +129,16 @@ module.exports = function (/** object */ options, /*Buffer*/ input) {
107
129
  }
108
130
  return data;
109
131
  } else {
110
- inflater.inflateAsync(function (result) {
111
- if (callback) {
112
- if (!crc32OK(result)) {
113
- callback(result, Utils.Errors.BAD_CRC()); //si added error
114
- } else {
115
- callback(result);
116
- }
132
+ inflater.inflateAsync(function (result, err) {
133
+ if (!callback) return;
134
+ if (err) {
135
+ // surface inflater/stream failures instead of validating
136
+ // the empty placeholder buffer against the CRC
137
+ callback(Buffer.alloc(0), err);
138
+ } else if (!crc32OK(result)) {
139
+ callback(result, Utils.Errors.BAD_CRC()); //si added error
140
+ } else {
141
+ callback(result);
117
142
  }
118
143
  });
119
144
  }
@@ -78,6 +78,16 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
78
78
 
79
79
  index += entry.header.centralHeaderSize;
80
80
 
81
+ // Reject archives that declare the same entry name twice. adm-zip keeps
82
+ // every entry in entryList but only the last in entryTable, so getEntry()
83
+ // (table) and extractAllTo() (list) could resolve one name to different
84
+ // content: an app that validates entry bytes via getEntry() before
85
+ // extracting could approve one file while a different one lands on disk
86
+ // (GHSA-p634-w6r4-rjp2). Fail closed on the ambiguity.
87
+ if (entry.entryName in entryTable) {
88
+ throw Utils.Errors.DUPLICATE_ENTRY(`"${entry.entryName}"`);
89
+ }
90
+
81
91
  entryList[i] = entry;
82
92
  entryTable[entry.entryName] = entry;
83
93
  }