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.
package/dist/esm/cli.js CHANGED
@@ -3213,7 +3213,7 @@ function summarizeAuth(auth) {
3213
3213
  var package_default = {
3214
3214
  name: "spamscanner",
3215
3215
  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.",
3216
- version: "7.0.2",
3216
+ version: "7.0.3",
3217
3217
  author: "Forward Email (https://forwardemail.net)",
3218
3218
  bin: {
3219
3219
  spamscanner: "./dist/esm/cli.js"
@@ -4721,7 +4721,7 @@ function sniff(buffer) {
4721
4721
  const at = (offset, bytes) => buffer.length >= offset + bytes.length && bytes.every((byte, i) => buffer[offset + i] === byte);
4722
4722
  const ascii = (offset, text) => at(offset, [...Buffer10.from(text, "latin1")]);
4723
4723
  const result = (type, executable = false) => ({ type, executable, archive: ARCHIVE_TYPES.has(type) });
4724
- if (ascii(0, "MZ")) {
4724
+ if (ascii(0, "MZ") && buffer.length >= 64 && at(buffer.readUInt32LE(60), [80, 69, 0, 0])) {
4725
4725
  return result("exe", true);
4726
4726
  }
4727
4727
  if (at(0, [127, 69, 76, 70])) {
@@ -4907,10 +4907,11 @@ function inspectAttachments(attachments = []) {
4907
4907
  if (parts.length >= 3 && EXECUTABLE_EXTENSIONS.has(extension) && DOCUMENT_EXTENSIONS.has(parts.at(-2))) {
4908
4908
  add("double_extension", `Attachment "${name}" has a document extension followed by a program extension`, { extension });
4909
4909
  }
4910
- if (EXECUTABLE_EXTENSIONS.has(extension) && !MACRO_EXTENSIONS.has(extension)) {
4910
+ const byName = EXECUTABLE_EXTENSIONS.has(extension) && !MACRO_EXTENSIONS.has(extension);
4911
+ if (detected?.executable && (detected.type !== "script" || !byName)) {
4912
+ 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 });
4913
+ } else if (byName) {
4911
4914
  add("executable", `Attachment "${name}" is a file type that runs code (.${extension})`, { extension });
4912
- } else if (detected?.executable) {
4913
- add(extension && !EXECUTABLE_EXTENSIONS.has(extension) ? "disguised_executable" : "executable", `Attachment "${name}" contains a program (${detected.type})${extension ? ` but is named .${extension}` : ""}`, { extension: detected.type });
4914
4915
  }
4915
4916
  if (!content) {
4916
4917
  if (MACRO_EXTENSIONS.has(extension)) {
@@ -6548,7 +6549,7 @@ var SpamScanner = class {
6548
6549
  message: `Link domain ${value} is listed in ${zone}`
6549
6550
  }));
6550
6551
  }
6551
- return { phishing, homographs };
6552
+ return { phishing, homographs, uncheckedHosts: seenHosts.size - checked.length };
6552
6553
  }
6553
6554
  async scanViruses(mail, config) {
6554
6555
  const settings = config.clamav === true ? {} : config.clamav;
@@ -6735,6 +6736,8 @@ ${typeof mail.text === "string" ? mail.text : ""}`, { maxLength: config.maxLengt
6735
6736
  // Grouped as in earlier versions.
6736
6737
  executables: attachments.filter((item) => ["executable", "disguised_executable", "double_extension", "rtl_override", "executable_in_archive"].includes(item.type)),
6737
6738
  macros: attachments.filter((item) => ["macro", "pdf_active", "rtf_object"].includes(item.type)),
6739
+ // Link hosts beyond phishing.maxHosts, which were not looked up.
6740
+ uncheckedHosts: links.uncheckedHosts,
6738
6741
  idnHomographAttack: {
6739
6742
  detected: links.homographs.length > 0,
6740
6743
  domains: links.homographs,