registry  /  @bobfrankston/rmfmail  /  1.2.117

@bobfrankston/rmfmail@1.2.117

Local-first email client with IMAP sync and standalone native app

AI Security Review

scanned 2h ago · by lpm-firewall-ai

Android runtime telemetry exfiltrates mail-account data to an unrelated logging host. The initialization path serializes the full IMAP configuration, including passwords when configured.

Static reason
One or more suspicious static signals were detected.; previous stored version diff introduced dangerous source
Trigger
Launching the Android mail client or adding/syncing an account.
Impact
Remote disclosure of email addresses, server metadata, and potentially IMAP passwords.
Mechanism
Unconsented remote logging of account configuration and credentials.
Attack narrative
On Android, `android-bootstrap.js` defines `vlog` as a fetch to `rmf39.aaz.lt`. Normal initialization calls it with account identifiers and `JSON.stringify(account.imap)`. IMAP configuration can contain the user's password, so this sends credentials and mail-account metadata to a third-party logging endpoint without an opt-in or an app-required destination. Similar log calls transmit email and host information during account setup and sync.
Rationale
Source inspection confirms a normal runtime path that transmits sensitive email-account configuration to an unrelated remote logging endpoint. This is concrete credential and data exfiltration, not a scanner-only lifecycle or network signal.
Evidence
packages/mailx-store-web/android-bootstrap.jspackages/mailx-store-web/worker-entry.jspackages/mailx-store-web/main-thread-host.jsbin/postinstall.jspackage.json
Network endpoints1
rmf39.aaz.lt/logit/

Decision evidence

public snapshot
AI called this Malicious at 97.0% confidence as Malware with low false-positive risk.
Evidence for block
  • `packages/mailx-store-web/android-bootstrap.js` sends logs to `https://rmf39.aaz.lt/logit/...`.
  • Normal Android initialization logs `JSON.stringify(account.imap)`, which includes configured IMAP credentials.
  • Account registration logs email addresses, IMAP hosts, ports, and authentication details to the same remote endpoint.
  • `vlog` runs during initialization, account setup, sync, and periodic polling without a user opt-in.
  • The install hook only creates scoped workspace symlinks; it is not the malicious behavior.
Evidence against
  • `bin/postinstall.js` limits writes to package-local `node_modules/@bobfrankston` symlinks.
  • Desktop update checks and Google API calls are package-aligned email-client functions.
  • No AI-agent control-surface mutation was found.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedProtestwareTelemetryUrlStrings
ManifestNo manifest risk signals triggered.
scanned 415 file(s), 16.1 MB of source, external domains: 127.0.0.1, accounts.google.com, api.anthropic.com, api.openai.com, autoconfig.thunderbird.net, bugs.webkit.org, bugzilla.mozilla.org, calendar.google.com, cdn.jsdelivr.net, cdnjs.cloudflare.com, contacts.google.com, cure53.de, developer.mozilla.org, developers.google.com, docs.microsoft.com, drafts.csswg.org, en.cppreference.com, feross.org, github.com, gmail.googleapis.com, graph.microsoft.com, html.spec.whatwg.org, lea.verou.me, mail.google.com, oauth2.googleapis.com, openjdk.java.net, opensource.org, people.googleapis.com, quilljs.com, rmf39.aaz.lt, tasks.google.com, tasks.googleapis.com, tiptap.dev, translate.google.com, websemantics.uk, www.cse.yorku.ca, www.googleapis.com, www.tiny.cloud, www.w3.org

Source & flagged code

13 flagged · loading source
package.jsonView file
scripts.postinstall = node bin/postinstall.js
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
scripts.postinstall = node bin/postinstall.js
Medium
Ambiguous Install Lifecycle Script

Install-time lifecycle script is not statically allowlisted and needs review.

package.jsonView on unpkg
bin/mailx.jsView file
54import net from "node:net"; L55: import { execSync } from "node:child_process"; L56: import { ports } from "@bobfrankston/miscinfo";
High
Child Process

Package source references child process execution.

bin/mailx.jsView on unpkg · L54
268// reg.exe value for `\"path\" \"%1\"` — double-backslash escapes for L269: // cmd.exe's shell layer, which strips one level before the value reaches L270: // reg.exe. Quoting %1 keeps `?` and `&` from being eaten by cmd before
High
Shell

Package source references shell execution.

bin/mailx.jsView on unpkg · L268
53Cross-file remote execution chain: bin/mailx.js spawns bin/popout-server.js; helper contains network access plus dynamic code execution. L53: import os from "node:os"; L54: import net from "node:net"; L55: import { execSync } from "node:child_process"; L56: import { ports } from "@bobfrankston/miscinfo"; ... L185: // Linux pickers read Name= from the .desktop file directly. L186: if (process.platform === "linux") { L187: const appsDir = path.join(os.homedir(), ".local", "share", "applications"); L188: const desktopPath = path.join(appsDir, "rmfmail.desktop"); ... L246: // (shipped in the npm package) to the per-app location below. L247: const __perAppBin = path.join(process.env.LOCALAPPDATA || "", "rmfmail", "bin"); L248: const __rmfmailtoExe = path.join(__perAppBin, "rmfmailto.exe"); ... L268: // reg.exe value for `\"path\" \"%1\"` — double-backslash escapes for
High
Cross File Remote Execution Context

Source spawns a local helper that also contains network and dynamic execution context; review data flow before blocking.

bin/mailx.jsView on unpkg · L53
2336clearInstanceFile(); L2337: const { spawn: spawnChild } = await import("child_process"); L2338: const child = spawnChild("rmfmail", [], { detached: true, stdio: "ignore", shell: true, windowsHide: true }); ... L2351: } L2352: // Auto-update action: run npm install then restart L2353: if (req._action === "performUpdate") {
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

bin/mailx.jsView on unpkg · L2336
53import os from "node:os"; L54: import net from "node:net"; L55: import { execSync } from "node:child_process"; L56: import { ports } from "@bobfrankston/miscinfo"; ... L185: // Linux pickers read Name= from the .desktop file directly. L186: if (process.platform === "linux") { L187: const appsDir = path.join(os.homedir(), ".local", "share", "applications"); L188: const desktopPath = path.join(appsDir, "rmfmail.desktop"); ... L246: // (shipped in the npm package) to the per-app location below. L247: const __perAppBin = path.join(process.env.LOCALAPPDATA || "", "rmfmail", "bin"); L248: const __rmfmailtoExe = path.join(__perAppBin, "rmfmailto.exe"); ... L268: // reg.exe value for `\"path\" \"%1\"` — double-backslash escapes for
Medium
Install Persistence

Source writes installer persistence such as shell profile or service configuration.

bin/mailx.jsView on unpkg · L53
client/lib/quill/quill.jsView file
1/*! For license information please see quill.js.LICENSE.txt */ L2: !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Quill=e():t.... L3: //# sourceMappingURL=quill.js.map
Low
Eval

Package source references a known benign dynamic code generation pattern.

client/lib/quill/quill.jsView on unpkg · L1
bin/lean-accounts.jsView file
137package = @bobfrankston/rmfmail; repositoryIdentity = mailx; dependency = jsonc-parser L137: const mod = await import(pathToFileURL(path.join(dir, "lib", "esm", "main.js")).href).catch(() => null) || L138: await import("jsonc-parser").catch(() => null); L139: if (mod) { parseJsonc = mod.parse; break; }
High
Copied Package Dependency Bridge

Package metadata claims a different repository identity while copied source loads a runtime dependency bridge.

bin/lean-accounts.jsView on unpkg · L137
136if (fs.existsSync(path.join(dir, "package.json"))) { L137: const mod = await import(pathToFileURL(path.join(dir, "lib", "esm", "main.js")).href).catch(() => null) || L138: await import("jsonc-parser").catch(() => null);
Medium
Dynamic Require

Package source references dynamic require/import behavior.

bin/lean-accounts.jsView on unpkg · L136
bin/build-bundles.mjsView file
5* mailx's msger custom protocol routes every fetch through one IPC channel L6: * (Rust → daemon stdin → response → stdout), so an ES module import cascade L7: * pays a multi-second roundtrip per file. With ~17 client-side modules each ... L148: logLevel: "info", L149: // .wasm files are inlined as base64 data URLs so the runtime can L150: // decode → Uint8Array → pass as initSqlJs({ wasmBinary }), bypassing L151: // sql.js's fetch(...) of the .wasm. Android WebView refuses to L152: // compile WASM fetched from file:// (even with AllowFileAccess /
Low
Weak Crypto

Package source references weak cryptographic algorithms.

bin/build-bundles.mjsView on unpkg · L5
bin/rmfmailto.exeView file
path = bin/rmfmailto.exe kind = native_binary sizeBytes = 310272 magicHex = [redacted]
Medium
Ships Native Binary

Package ships native binary artifacts.

bin/rmfmailto.exeView on unpkg
packages/mailx-service/index.jsView file
matchType = previous_version_dangerous_delta matchedPackage = @bobfrankston/rmfmail@1.2.116 matchedIdentity = npm:QGJvYmZyYW5rc3Rvbi9ybWZtYWls:1.2.116 similarity = 0.917 summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta

This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.

packages/mailx-service/index.jsView on unpkg

Findings

1 Critical6 High8 Medium8 Low
CriticalPrevious Version Dangerous Deltapackages/mailx-service/index.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processbin/mailx.js
HighShellbin/mailx.js
HighCopied Package Dependency Bridgebin/lean-accounts.js
HighCross File Remote Execution Contextbin/mailx.js
HighRuntime Package Installbin/mailx.js
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumDynamic Requirebin/lean-accounts.js
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencebin/mailx.js
MediumProtestware
MediumShips Native Binarybin/rmfmailto.exe
MediumStructural Risk Force Deep Review
LowScripts Present
LowEvalclient/lib/quill/quill.js
LowWeak Cryptobin/build-bundles.mjs
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowTelemetry
LowUrl Strings