spamscanner 7.0.2 → 7.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.
@@ -2172,7 +2172,7 @@ function sniff(buffer) {
2172
2172
  const at = (offset, bytes) => buffer.length >= offset + bytes.length && bytes.every((byte, i) => buffer[offset + i] === byte);
2173
2173
  const ascii = (offset, text) => at(offset, [...import_node_buffer.Buffer.from(text, "latin1")]);
2174
2174
  const result = (type, executable = false) => ({ type, executable, archive: ARCHIVE_TYPES.has(type) });
2175
- if (ascii(0, "MZ")) {
2175
+ if (ascii(0, "MZ") && buffer.length >= 64 && at(buffer.readUInt32LE(60), [80, 69, 0, 0])) {
2176
2176
  return result("exe", true);
2177
2177
  }
2178
2178
  if (at(0, [127, 69, 76, 70])) {
@@ -2351,10 +2351,11 @@ function inspectAttachments(attachments = []) {
2351
2351
  if (parts.length >= 3 && EXECUTABLE_EXTENSIONS.has(extension) && DOCUMENT_EXTENSIONS.has(parts.at(-2))) {
2352
2352
  add("double_extension", `Attachment "${name}" has a document extension followed by a program extension`, { extension });
2353
2353
  }
2354
- if (EXECUTABLE_EXTENSIONS.has(extension) && !MACRO_EXTENSIONS.has(extension)) {
2354
+ const byName = EXECUTABLE_EXTENSIONS.has(extension) && !MACRO_EXTENSIONS.has(extension);
2355
+ if (detected?.executable && (detected.type !== "script" || !byName)) {
2356
+ add(extension && !EXECUTABLE_EXTENSIONS.has(extension) ? "disguised_executable" : "executable", `Attachment "${name}" contains a program (${detected.type})${extension && extension !== detected.type ? ` but is named .${extension}` : ""}`, { extension: detected.type });
2357
+ } else if (byName) {
2355
2358
  add("executable", `Attachment "${name}" is a file type that runs code (.${extension})`, { extension });
2356
- } else if (detected?.executable) {
2357
- add(extension && !EXECUTABLE_EXTENSIONS.has(extension) ? "disguised_executable" : "executable", `Attachment "${name}" contains a program (${detected.type})${extension ? ` but is named .${extension}` : ""}`, { extension: detected.type });
2358
2359
  }
2359
2360
  if (!content) {
2360
2361
  if (MACRO_EXTENSIONS.has(extension)) {
@@ -5441,7 +5442,7 @@ var init_package = __esm({
5441
5442
  package_default = {
5442
5443
  name: "spamscanner",
5443
5444
  description: "Spam, phishing and malware filter for email in any language: a trainable classifier, link and attachment checks, SPF/DKIM/DMARC, and an optional AI second opinion from any LLM, including local Ollama models. Works as a library, CLI, Postfix milter or HTTP API.",
5444
- version: "7.0.2",
5445
+ version: "7.0.3",
5445
5446
  author: "Forward Email (https://forwardemail.net)",
5446
5447
  bin: {
5447
5448
  spamscanner: "./dist/esm/cli.js"
@@ -7235,7 +7236,7 @@ var init_src = __esm({
7235
7236
  message: `Link domain ${value} is listed in ${zone}`
7236
7237
  }));
7237
7238
  }
7238
- return { phishing, homographs };
7239
+ return { phishing, homographs, uncheckedHosts: seenHosts.size - checked.length };
7239
7240
  }
7240
7241
  async scanViruses(mail, config) {
7241
7242
  const settings = config.clamav === true ? {} : config.clamav;
@@ -7422,6 +7423,8 @@ ${typeof mail.text === "string" ? mail.text : ""}`, { maxLength: config.maxLengt
7422
7423
  // Grouped as in earlier versions.
7423
7424
  executables: attachments.filter((item) => ["executable", "disguised_executable", "double_extension", "rtl_override", "executable_in_archive"].includes(item.type)),
7424
7425
  macros: attachments.filter((item) => ["macro", "pdf_active", "rtf_object"].includes(item.type)),
7426
+ // Link hosts beyond phishing.maxHosts, which were not looked up.
7427
+ uncheckedHosts: links.uncheckedHosts,
7425
7428
  idnHomographAttack: {
7426
7429
  detected: links.homographs.length > 0,
7427
7430
  domains: links.homographs,