pompelmi 0.14.0 → 0.15.0-dev.27

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.
@@ -3191,7 +3191,8 @@ function isZipLike(buf) {
3191
3191
  function lastIndexOfEOCD(buf, window) {
3192
3192
  const sig = Buffer.from([0x50, 0x4b, 0x05, 0x06]);
3193
3193
  const start = Math.max(0, buf.length - window);
3194
- return buf.lastIndexOf(sig, buf.length - 1, start);
3194
+ const idx = buf.lastIndexOf(sig, Math.min(buf.length - sig.length, buf.length - 1));
3195
+ return idx >= start ? idx : -1;
3195
3196
  }
3196
3197
  function hasTraversal(name) {
3197
3198
  return name.includes('../') || name.includes('..\\') || name.startsWith('/') || /^[A-Za-z]:/.test(name);
@@ -3208,7 +3209,7 @@ function createZipBombGuard(opts = {}) {
3208
3209
  const eocdPos = lastIndexOfEOCD(buf, cfg.eocdSearchWindow);
3209
3210
  if (eocdPos < 0 || eocdPos + 22 > buf.length) {
3210
3211
  // ZIP but no EOCD — malformed or polyglot → suspicious
3211
- matches.push({ rule: 'zip_eocd_not_found', severity: 'suspicious' });
3212
+ matches.push({ rule: 'zip_eocd_not_found', severity: 'medium' });
3212
3213
  return matches;
3213
3214
  }
3214
3215
  const totalEntries = r16(buf, eocdPos + 10);
@@ -3216,7 +3217,7 @@ function createZipBombGuard(opts = {}) {
3216
3217
  const cdOffset = r32(buf, eocdPos + 16);
3217
3218
  // Bounds check
3218
3219
  if (cdOffset + cdSize > buf.length) {
3219
- matches.push({ rule: 'zip_cd_out_of_bounds', severity: 'suspicious' });
3220
+ matches.push({ rule: 'zip_cd_out_of_bounds', severity: 'medium' });
3220
3221
  return matches;
3221
3222
  }
3222
3223
  // Iterate central directory entries
@@ -3242,36 +3243,36 @@ function createZipBombGuard(opts = {}) {
3242
3243
  sumUnc += uncSize;
3243
3244
  seen++;
3244
3245
  if (name.length > cfg.maxEntryNameLength) {
3245
- matches.push({ rule: 'zip_entry_name_too_long', severity: 'suspicious', meta: { name, length: name.length } });
3246
+ matches.push({ rule: 'zip_entry_name_too_long', severity: 'medium', meta: { name, length: name.length } });
3246
3247
  }
3247
3248
  if (hasTraversal(name)) {
3248
- matches.push({ rule: 'zip_path_traversal_entry', severity: 'suspicious', meta: { name } });
3249
+ matches.push({ rule: 'zip_path_traversal_entry', severity: 'medium', meta: { name } });
3249
3250
  }
3250
3251
  // move to next entry
3251
3252
  ptr = nameEnd + exLen + cmLen;
3252
3253
  }
3253
3254
  if (seen !== totalEntries) {
3254
3255
  // central dir truncated/odd, still report what we found
3255
- matches.push({ rule: 'zip_cd_truncated', severity: 'suspicious', meta: { seen, totalEntries } });
3256
+ matches.push({ rule: 'zip_cd_truncated', severity: 'medium', meta: { seen, totalEntries } });
3256
3257
  }
3257
3258
  // Heuristics thresholds
3258
3259
  if (seen > cfg.maxEntries) {
3259
- matches.push({ rule: 'zip_too_many_entries', severity: 'suspicious', meta: { seen, limit: cfg.maxEntries } });
3260
+ matches.push({ rule: 'zip_too_many_entries', severity: 'medium', meta: { seen, limit: cfg.maxEntries } });
3260
3261
  }
3261
3262
  if (sumUnc > cfg.maxTotalUncompressedBytes) {
3262
3263
  matches.push({
3263
3264
  rule: 'zip_total_uncompressed_too_large',
3264
- severity: 'suspicious',
3265
+ severity: 'medium',
3265
3266
  meta: { totalUncompressed: sumUnc, limit: cfg.maxTotalUncompressedBytes }
3266
3267
  });
3267
3268
  }
3268
3269
  if (sumComp === 0 && sumUnc > 0) {
3269
- matches.push({ rule: 'zip_suspicious_ratio', severity: 'suspicious', meta: { ratio: Infinity } });
3270
+ matches.push({ rule: 'zip_suspicious_ratio', severity: 'medium', meta: { ratio: Infinity } });
3270
3271
  }
3271
3272
  else if (sumComp > 0) {
3272
3273
  const ratio = sumUnc / Math.max(1, sumComp);
3273
3274
  if (ratio >= cfg.maxCompressionRatio) {
3274
- matches.push({ rule: 'zip_suspicious_ratio', severity: 'suspicious', meta: { ratio, limit: cfg.maxCompressionRatio } });
3275
+ matches.push({ rule: 'zip_suspicious_ratio', severity: 'medium', meta: { ratio, limit: cfg.maxCompressionRatio } });
3275
3276
  }
3276
3277
  }
3277
3278
  return matches;
@@ -3279,5 +3280,29 @@ function createZipBombGuard(opts = {}) {
3279
3280
  };
3280
3281
  }
3281
3282
 
3282
- export { CommonHeuristicsScanner, createZipBombGuard, mapMatchesToVerdict, prefilterBrowser, scanFiles, scanFilesWithHeuristicsAndYara, scanFilesWithRemoteYara, scanFilesWithYara, useFileScanner, validateFile };
3283
+ const MB = 1024 * 1024;
3284
+ const DEFAULT_POLICY = {
3285
+ includeExtensions: ['zip', 'png', 'jpg', 'jpeg', 'pdf'],
3286
+ allowedMimeTypes: ['application/zip', 'image/png', 'image/jpeg', 'application/pdf', 'text/plain'],
3287
+ maxFileSizeBytes: 20 * MB,
3288
+ timeoutMs: 5000,
3289
+ concurrency: 4,
3290
+ failClosed: true
3291
+ };
3292
+ function definePolicy(input = {}) {
3293
+ const p = { ...DEFAULT_POLICY, ...input };
3294
+ if (!Array.isArray(p.includeExtensions))
3295
+ throw new TypeError('includeExtensions must be string[]');
3296
+ if (!Array.isArray(p.allowedMimeTypes))
3297
+ throw new TypeError('allowedMimeTypes must be string[]');
3298
+ if (!(Number.isFinite(p.maxFileSizeBytes) && p.maxFileSizeBytes > 0))
3299
+ throw new TypeError('maxFileSizeBytes must be > 0');
3300
+ if (!(Number.isFinite(p.timeoutMs) && p.timeoutMs > 0))
3301
+ throw new TypeError('timeoutMs must be > 0');
3302
+ if (!(Number.isInteger(p.concurrency) && p.concurrency > 0))
3303
+ throw new TypeError('concurrency must be > 0');
3304
+ return p;
3305
+ }
3306
+
3307
+ export { CommonHeuristicsScanner, DEFAULT_POLICY, createZipBombGuard, definePolicy, mapMatchesToVerdict, prefilterBrowser, scanFiles, scanFilesWithHeuristicsAndYara, scanFilesWithRemoteYara, scanFilesWithYara, useFileScanner, validateFile };
3283
3308
  //# sourceMappingURL=pompelmi.esm.js.map