Security & privacy in ZeroIn

What is built, how it is verified, and what is not yet built

Last updated: 12 September 2026
Describes the current closed beta

Most of the protections described here are not visible during normal use. A client that blocks trackers looks the same as one that receives none, and a message that is prevented from reporting back looks like any other message. This page documents them for that reason.

It follows two principles: describe only what the build verifies, and list what is not yet built. The final section covers the latter.

1 What senders can learn about you

HTML email is a document written by the sender, and by default such a document can report back to its author when it is loaded. This section describes how ZeroIn limits that.

  • Images and other remote content are fetched while your mail syncs, not when you open a message. A tracking pixel records the time it is fetched. Fetching during sync tells the sender only that the message was delivered, which they already know.
  • Known trackers are never fetched, at any security level. The blocklist is built into the app and is not downloaded at runtime, since downloading it would itself be a request that reveals the installation.
  • Tracking pixels leave no placeholder. They take up no visible space, so instead of showing an empty box, ZeroIn counts and reports them.
  • Blocked images are reported per message, with Load once and Always allow this sender options. The banner is not shown when the only blocked item is a tracking beacon, so that it appears only when there is visible content to load and remains meaningful when it does.
  • Read receipts are never sent automatically. When a sender requests one, ZeroIn shows a button along with the address the receipt would be sent to, which may differ from the sender's address.
  • Changing the setting re-renders affected messages in the background. Re-rendering when a message is opened would fetch images at the moment it is read, which is what this design avoids.
◆
Two exceptions, both user-initiated. Load once and clicking a single blocked image are the only actions that fetch content while a message is open. Both show a notice first, because either one lets the sender know the message is being read.

2 Sender verification

  • The “verified sender” mark means your own mail server verified the message, not that the message claims to be verified. Authentication results inside a message are plain text that anyone, including the sender, can write; ZeroIn relies only on the results added by your provider.
  • The mark requires the verified domain to match the From address shown. A lookalike domain can pass authentication checks for itself. An earlier version of ZeroIn displayed the mark in that case; this has been corrected, as a misleading indicator is less useful than none.
  • There are three states: verified, failed, and no indication. Much legitimate mail from small senders and mailing lists falls into the third state, and marking it as suspicious would produce far more false warnings than correct ones.

3 Phishing detection

  • Sixteen signals are weighted and scored on your device. They include a display name imitating one of your contacts, a From domain closely resembling one you correspond with, a sign-in link whose destination differs from its text, urgent language, and a login form in the message body.
  • No information about the message leaves your device for scoring — no hash, URL or sender. The scoring component receives only a description of the message and has no access to the network.
  • Warnings describe the specific issue in a sentence about that message. Generic warnings tend to be dismissed without being read.
  • Weights are set so that no weak signal triggers a warning on its own. A different Reply-To address is normal for mailing lists, and urgent wording appears in legitimate bank mail. A warning requires a stronger indicator, such as impersonation or a misleading link.
  • Messages scored as dangerous have reduced privileges. Remote content remains blocked, every link requires confirmation, and one-click unsubscribe is disabled, since responding to a phishing message confirms that the address is active.

5 Message rendering

  • HTML is sanitised on the parsed document rather than by pattern matching on text, so the content that is checked is the same content that is displayed. Sanitisation uses allowlists throughout, not blocklists.
  • Scripts, forms, embedded objects and event handlers are removed. The message body runs under a content policy that permits only the app's own code, which a sender cannot imitate.
  • From inside the renderer, a message cannot access the network, read files on your device, or navigate to any document other than the one loaded.
  • Stylesheets are also parsed. This caught a background image inside a shorthand declaration that an earlier pattern-matching implementation had missed.
  • Malformed messages are displayed with a warning rather than crashing or rendering blank. Limits apply to nesting depth and to the number of parts, headers and characters; a message that exceeds a limit is shown as received, with a note describing the problem.
  • Line breaks cannot be injected into headers, either in outgoing mail or in incoming encoded headers.
  • The parser is fuzz-tested. A corpus of malformed messages is mutated and replayed a million times, with no unhandled errors, hangs or blank renders.

6 Outgoing mail

  • Location and time metadata is removed from photos before sending — GPS coordinates, timestamp, camera make, model and serial number, and the owner's name where present. Images are not re-encoded, so their quality is unchanged. Orientation and colour profile are retained, because removing orientation would display the photo rotated for the recipient and lead users to disable the feature.
  • Links that open a pre-filled message cannot attach files from your device, change the sender, or add hidden recipients through line breaks. They only fill in a compose window that you review before sending.
  • Quoted replies include the original text, not its HTML, so the original sender's tracking pixel is not passed on to new recipients under your name.
  • Pre-send checks appear only for specific issues: a single recipient at a domain no other recipient shares, a mentioned attachment that is missing, or a Bcc address that also appears in To. Limiting checks to these cases keeps the warnings meaningful.
  • Outgoing mail does not identify ZeroIn. There is no X-Mailer header, no signature, and no identifying text in the message structure. Three such identifiers were found in internal message parts and removed.

7 Attachments

  • Filenames are displayed accurately. The right-to-left override technique, which makes a file named invoice.pdf.exe appear to end in .pdf, is neutralised and visibly marked rather than silently removed.
  • Type mismatches are described by their effect — for example “This is a program, not a .pdf file” rather than “magic bytes differ” — and assessed conservatively: a .docx file is a ZIP container, so ZIP content in a .docx is not flagged.
  • Attachments are never passed to the operating system to open. Previews render within the app, and confirmation is requested when saving a potentially risky file, since that is the step before it can be opened from disk.
  • Archives are opened with limits on nesting depth, number of entries and compression ratio, so an archive bomb produces an error message instead of freezing the app.

8 Network connections

  • Every outbound request declares its purpose, and hosts not permitted for that purpose are refused. There is no general-purpose or default-allow category, so a request without a declared purpose fails rather than succeeding unnoticed.
  • Unencrypted connections are refused in all builds, including development builds, so test builds cannot do anything the released app cannot.
  • Mail connections must be encrypted. Plaintext ports are upgraded, and server capabilities advertised before the upgrade are re-read afterwards rather than trusted. A downgrade ends the connection unless you have explicitly allowed it for that account.
  • The network log records hosts, not full URLs. Remote-content URLs can contain tokens unique to the recipient, and mail API URLs can contain search terms and message IDs, so recording them would expose the information the log is meant to protect.
◈
Network Log Settings → Reports & Statistics → Network Log lists every request made in the current session, its purpose, and whether it was allowed or refused, with the reason. The app also includes a complete list of the connections it can make, generated from the same code that enforces the rules, so the two remain consistent.

9 Data on your device

  • Credentials are stored in the platform keystore — Keychain on macOS and iOS, libsecret on Linux, Credential Manager on Windows — not in the app's own files.
  • Logs are scrubbed when written, not when displayed. The stored log can be attached to bug reports, so tokens and passwords are removed before they reach it. The app's internal objects log identifiers only, never subjects, addresses or filenames.
  • Screenshots and screen recording can be blocked, including the app-switcher thumbnail the system captures automatically.
  • Android backups are disabled, so the mail store is not included in cloud or USB backups.
  • Privacy mode pixelates senders, subjects, message bodies and avatars on demand, and is enabled automatically while a feedback screenshot is captured.
▲
The message database is not encrypted. Credentials are stored in the keystore, but message bodies, subjects and attachments can be read by any process with access to the file. See section 13, where this is the most significant item.

10 Diagnostics and updates

  • Crash reporting is opt-in and off by default, including in the beta, which asks once at first launch and stores your choice. If you decline, the app works the same and the reporting library is not started. No usage analytics are collected.
  • A crash is written to a local file, not sent. The next time you open ZeroIn, it shows the full report, lets you edit it, and asks whether to send it. Closing the window counts as Discard, and the file is deleted in either case. Reports are sent only with your confirmation.
  • Screenshots attached to bug reports are shown to you first — the exact image at full size, with names and message text pixelated — and can be removed before sending.
  • Network breadcrumbs are removed from reports entirely, because the sequence of servers contacted can reveal information about your mailbox.
  • Update checks run only when you request one, not at every launch. The request contains no identifying information, not even your version number, since the comparison is done locally. The check can be disabled.
  • The app does not install updates itself. New versions are downloaded and installed in the usual way for your system, so your platform's signature verification applies.
  • No tracking, no usage analytics, and no “Sent from ZeroIn” text in your mail.

11 Security levels

A single security level sets the overall configuration. It does not disable core protections: controls are divided into two tiers, and the level affects only one of them.

Baseline — always on

Not configurable at any security level: HTML sanitisation, the permitted URL schemes for links, encrypted-only connections, no automatic read receipts, the tracker blocklist, and parser limits. There is no legitimate reason to disable these controls.

Adjustable settings

Controls that trade convenience against protection: which remote content loads, how much confirmation links require, and whether profile pictures are fetched. The level sets all of them together, and each can also be changed individually.

LevelWhat it changes
Relaxed Remote content loads during sync, except anything on the tracker list. Links are checked, and deceptive links still require confirmation. The baseline is unchanged.
Normal The default. As Relaxed, with additional confirmation for links that do not match their displayed text, and stricter handling of messages scored as suspicious.
Strict Remote content is blocked by default and loaded per message on request. Profile-picture lookups and sender-signature DNS lookups are disabled, so a new installation connects only to your mail provider.
✓
The most permissive level retains all baseline protections. Each baseline control is covered by a test that runs under all three levels, so this is enforced by the build rather than depending on default settings.

Two features enabled by default

Profile pictures (looked up per correspondent from an avatar service) and the DNS lookups used to verify a sender's signature. Both disclose to a third party who you correspond with, though not the content of your mail. Each can be disabled individually, and selecting Strict disables both.

Unimplemented settings are labelled

Unfinished features show a Not available yet label instead of a control that has no effect. A test fails the build if first-run setup offers one.

12 How this is verified

  • Every push runs a blocking check: the attack corpus against the HTML sanitiser, a scan for network requests made outside the central request handler, the baseline tests under all three levels, and assertions on the Android manifest.
  • Each release generates a report from the enforced values, so published claims match the code they describe.
  • The attack corpus is stored as data and read by both the tests and the report, so the report covers only what the tests verify.

13 Current limitations

The following are not yet implemented in the current build. This list is updated as work progresses.

  • The message database is not encrypted at rest. Credentials are stored in the platform keystore, but message bodies, subjects and attachments can be read by any process with access to the file. A design exists but work has not started, because the current database engine does not support encryption and adding it requires replacing the engine.
  • The rendered-message cache stores an unencrypted copy of each message you have opened, for the same reason.
  • There is no quarantine. Suspicious messages are marked and have reduced privileges, but are not stored separately, and there is no digest for review.
  • Phishing weights are based on reasoning rather than measurement. No detection or false-positive rate is claimed, as that would require a labelled corpus of real mail, which the project does not have.
  • Metadata is not removed from GIF or TIFF images. GIF files contain only comment blocks; TIFF stores metadata throughout the file and would require a complete rewriter rather than the container-level editing used for other formats.
  • Android release builds are not yet signed with a release key.
  • Per-release network capture is not yet running. It requires a dedicated test account and device; until these are available, the job reports not configured rather than passed.
  • There is no licensing — no tiers, keys or activation. If this changes, verification will take place locally without a server. The build currently asserts that no download-and-run path exists.
◆
Why this list is published A security page that lists only working features does not show where protection ends. Documenting the limitations makes it clear what the app does and does not protect against.