molt-cli 1.0.2 → 1.0.3

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 (2) hide show
  1. package/cli.js +33 -1
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -338,13 +338,45 @@ function extractTarGz(tarGzPath, destDir) {
338
338
  const extract = tar.extract();
339
339
  const gunzip = zlib.createGunzip();
340
340
 
341
+ const MAX_EXTRACTED_SIZE = 50 * 1024 * 1024; // 50MB max decompressed
342
+ const MAX_FILES = 500; // max files in package
343
+ let totalSize = 0;
344
+ let fileCount = 0;
345
+ const resolvedDest = path.resolve(destDir);
346
+
341
347
  extract.on('entry', (header, stream, next) => {
342
- const filePath = path.join(destDir, header.name);
348
+ fileCount++;
349
+ if (fileCount > MAX_FILES) {
350
+ stream.destroy();
351
+ return reject(new Error(`Too many files in package (max ${MAX_FILES}). Aborting.`));
352
+ }
353
+
354
+ // Path traversal protection: resolve and verify within destDir
355
+ const filePath = path.resolve(destDir, header.name);
356
+ if (!filePath.startsWith(resolvedDest + path.sep) && filePath !== resolvedDest) {
357
+ stream.resume(); // skip malicious entry
358
+ console.log(` ${C.red}⚠ Skipping suspicious path: ${header.name}${C.reset}`);
359
+ return next();
360
+ }
361
+
362
+ // Skip symlinks (potential attack vector)
363
+ if (header.type === 'symlink' || header.type === 'link') {
364
+ stream.resume();
365
+ return next();
366
+ }
367
+
343
368
  if (header.type === 'directory') {
344
369
  fs.mkdirSync(filePath, { recursive: true });
345
370
  stream.resume();
346
371
  next();
347
372
  } else {
373
+ // Tar bomb protection: track decompressed size
374
+ totalSize += header.size || 0;
375
+ if (totalSize > MAX_EXTRACTED_SIZE) {
376
+ stream.destroy();
377
+ return reject(new Error(`Package too large when extracted (>${MAX_EXTRACTED_SIZE / 1024 / 1024}MB). Possible tar bomb.`));
378
+ }
379
+
348
380
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
349
381
  const out = fs.createWriteStream(filePath);
350
382
  stream.pipe(out);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "molt-cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "CLI for MolTunes — the AI agent skill marketplace",
5
5
  "main": "cli.js",
6
6
  "bin": {