Zero-Breach-Toolkit
A free, open-source check for traces of known mercenary spyware (Pegasus, Predator, Graphite, Candiru and others) on computers, Android phones and iPhone backups.
- Read-only. It does not modify source evidence or system settings. It writes only temporary database snapshots and the reports you ask for.
- No network requests during a scan. It never looks up spyware addresses and has no upload feature. Python network calls are blocked and redirected paths are refused. This is not an operating-system network sandbox; see PRIVACY.md.
- States its limits. Every report says what was found, how strong the evidence is, and what could not be checked. A clean result is never presented as proof that you are safe.
Made by archivegenocide. Built on Zero Breach.
If you think you are being targeted right now, get expert help first. You do not need to run this tool before asking. Journalists, activists, human-rights defenders and civil society can contact the Access Now Digital Security Helpline (free, 24/7, many languages) or Amnesty International's Security Lab.
Step-by-step guide (no technical experience needed)
You do not need a GitHub account or any technical knowledge. You need a Windows or Mac computer and about 20 minutes. Phones are checked by connecting them to the computer.
What do you want to check? This Windows computer · This Mac · An Android phone · An iPhone
Windows
Set up (only the first time)
- Go to python.org/downloads and click the yellow Download Python button. Open the downloaded file.
- On the first screen of the installer, tick "Add python.exe to PATH" at the bottom, then click Install Now. Wait until it says "Setup was successful".
- On this page, click the green Code button near the top, then Download ZIP.
- Open your Downloads folder, right-click Zero-Breach-Toolkit-main.zip and choose Extract All, then Extract.
Run the check
- Close your web browsers and chat apps (Chrome, Edge, WhatsApp, Signal…).
- Open the Zero-Breach-Toolkit-main folder (if there is another folder with the same name inside, open that one too), then the scan folder, and double-click run-scan.cmd. If Windows shows a warning, click Run (or More info, then Run anyway).
- A menu appears. Type the number next to Update the indicator lists and press Enter,
then type
yand press Enter. When it finishes, press Enter. - Press Enter again to start This computer - standard check. It takes about 15 minutes.
- Read the result at the end (see What the result means). A copy is saved in the findings folder inside Zero-Breach-Toolkit-main.
Mac
Set up (only the first time)
- Go to python.org/downloads, click Download Python, open the downloaded file and follow the installer. When it finishes, open Finder → Applications → Python 3 and double-click Install Certificates.command (without it, updating the indicator lists fails).
- On this page, click the green Code button, then Download ZIP. It appears in your Downloads folder as Zero-Breach-Toolkit-main (if it is still a .zip file, double-click it).
- Open System Settings → Privacy & Security → Full Disk Access, click +, choose Applications → Utilities → Terminal, and turn it on. Without this, macOS hides Safari's records from the check.
Run the check
- Close your web browsers and chat apps.
- Open Terminal (press Cmd+Space, type
Terminal, press Enter). Copy this line, paste it into Terminal and press Enter:cd ~/Downloads/Zero-Breach-Toolkit-main && python3 -X utf8 scan/zero-breach-toolkit.py - A menu appears. Type the number next to Update the indicator lists and press Enter,
then type
yand press Enter. When it finishes, press Enter. - Press Enter again to start This computer - standard check. It takes about 15 minutes.
- To keep a copy of the result, type
3and press Enter, typereport.txtand press Enter. It is saved in the Zero-Breach-Toolkit-main folder. Type0to finish.
Linux
Set up (only the first time)
- Open a terminal (on most desktops, press Ctrl+Alt+T). Python 3 is usually already
installed; check with
python3 --version. If it is missing, install it with your package manager, for examplesudo dnf install python3(Fedora),sudo apt install python3(Ubuntu, Debian, Mint) orsudo pacman -S python(Arch). - On this page, click the green Code button, then Download ZIP. In your Downloads folder, right-click the zip and choose Extract Here, so that you have a folder named Zero-Breach-Toolkit-main.
Run the check
- Close your web browsers and chat apps.
- Copy this line, paste it into the terminal and press Enter:
cd ~/Downloads/Zero-Breach-Toolkit-main && python3 -X utf8 scan/zero-breach-toolkit.py - A menu appears. Type the number next to Update the indicator lists and press Enter,
then type
yand press Enter. When it finishes, press Enter. - Press Enter again to start This computer - standard check. It takes about 15 minutes.
- To keep a copy of the result, type
3and press Enter, typereport.txtand press Enter. It is saved in the Zero-Breach-Toolkit-main folder. Type0to finish.
You do not need sudo to run the check. It reads your own account's records; run with
sudo, it may look at the root account's browsers instead of yours.
Android phone
First do the Set up steps for Windows or Mac above.
On the phone
- Open Settings → About phone and tap Build number seven times, until it says you are a developer. (On Samsung: Settings → About phone → Software information → Build number.)
- Go back to Settings, open Developer options (often under System) and turn on USB debugging.
- Connect the phone to the computer with a USB cable that carries data (some cables only charge). Unlock the phone. When it asks Allow USB debugging?, tick Always allow and tap Allow.
On the computer
Start Zero Breach (Windows: double-click run-scan.cmd; Mac: step 5 of the Mac guide).
In the menu, type the number next to A phone and press Enter, then type
2(Collect from an Android phone connected by USB now) and press Enter.Press Enter to save the collection on your Desktop, then type
YESand press Enter.The collector asks a few questions. Use the arrow keys and Enter to answer:
It asks Choose Backup Only SMS Download copies of apps Only non-system packages Remove copies of apps signed with a trusted certificate No Intrusion Logs No Hash files No Anything else No If the phone shows Back up my data, tap it (leave the password empty). Keep the phone unlocked until the collection finishes.
The check starts by itself and shows the result.
When you are done, turn USB debugging off again on the phone.
iPhone
First do the Set up steps for Windows or Mac above.
Make a backup on the computer. Connect the iPhone with a cable and tap Trust on the phone.
- Windows: install Apple Devices from the Microsoft Store, open it and select the iPhone.
- Mac: open Finder and select the iPhone in the sidebar.
Choose Back up all of the data on your iPhone to this computer, tick Encrypt local backup, choose a password you will remember, and click Back Up Now. Wait until it finishes.
Open the backup folder:
- Windows: press Windows key + R, paste
%USERPROFILE%\Apple\MobileSync\Backupand press Enter. - Mac: in Finder, choose Go → Go to Folder, paste
~/Library/Application Support/MobileSync/Backupand press Enter.
Inside is a folder with a long name of letters and numbers: that is your backup.
- Windows: press Windows key + R, paste
Start Zero Breach. In the menu, type the number next to A phone, press Enter, type
1and press Enter.Drag the backup folder (the one with the long name) into the Zero Breach window and press Enter.
When asked whether the backup is password-protected, type
yand press Enter, then type the backup password (nothing appears while you type) and press Enter.
If something goes wrong
| What you see | What to do |
|---|---|
'python' is not recognized or nothing happens on Windows |
Run the Python installer again, choose Modify, and make sure Add Python to environment variables is ticked. Restart the computer. |
No such file or directory on a Mac |
Type python3 -X utf8 (with a space at the end) in Terminal, then drag the file zero-breach-toolkit.py from the toolkit's scan folder into Terminal and press Enter. This works from any folder. |
A folder named candiru in the download |
That is part of the toolkit: third_party/candiru holds the published detection rules for Candiru's spyware, not the spyware. Leave it in place; if it was deleted, download the toolkit again. |
| "encrypted iPhone backups require optional cryptography" after installing it | It went into a different Python. Install it with the same command you start the check with (python3 -m pip install --require-hashes -r requirements-backups.txt on a Mac), from the toolkit folder. |
command not found: python3 |
Install Python from python.org (step 1), then close and reopen Terminal. |
Updating the indicator lists fails on a Mac (CERTIFICATE_VERIFY_FAILED) |
Open Finder → Applications → Python 3 and double-click Install Certificates.command, then update again. Full Disk Access does not affect updating. |
| Android: the collector finds no phone | Unlock the phone, use a different cable or USB port, and check Allow USB debugging was accepted. Unplug and plug in again. |
| iPhone: "wrong password" | Use the password chosen when Encrypt local backup was first turned on. If it is forgotten, it can be reset on the iPhone (Settings → General → Transfer or Reset iPhone → Reset → Reset All Settings), then make a new backup. |
| Safari "could not be checked" on a Mac | Give Terminal Full Disk Access (Mac step 3), close Terminal, open it again and run the check again. |
Still stuck? Ask in the issues (do not post your report there; it contains private details).
What the result means
- "No known indicators found": nothing from the published spyware lists was found in the places the tool could check. It is not proof that the device is clean: read the list of places that could not be checked.
- "Something matched": this means look closer, not you are infected. Do not delete anything and do not visit the address it names. Keep the report and contact the Access Now Digital Security Helpline (free, 24/7).
- The report never leaves your computer unless you send it to someone yourself.
What it checks
Windows
No administrator rights are needed.
| Where | What it looks for |
|---|---|
| Browsers at their default locations: Chrome, Edge and Brave (including beta, dev, canary and nightly channels), Chromium, Vivaldi, Opera, Opera GX, Arc, Yandex; Firefox, LibreWolf, Waterfox, Floorp, Zen, Pale Moon, Tor Browser | indicator addresses in history, cookies, connection records, HSTS, bookmarks, downloads, site storage and caches, per profile |
| Desktop apps with a built-in Chromium browser | supported history, cookie and storage records; raw app web caches are skipped and reported as a gap |
| Downloaded files | the website each file came from (the "Mark of the Web" stamp) |
| The Win+R box | commands people were tricked into pasting by fake "verify you are human" pages |
| Antivirus status and Microsoft Defender history | registered antivirus products and their reported status; past Defender detections, protection-off events and added exclusions |
| PowerShell log | scripts that named a spyware address, or downloaded and ran code |
| Programs listed by Windows | existing files named in the shim cache and the Windows 11 launch list, compared with published sample fingerprints; not a complete execution history |
| Prefetch and Amcache | supported Prefetch executable-name records and Amcache file inventory; the program files they name are never opened |
| Selected user folders | fingerprints of candidate files, within size and directory limits |
| DNS cache, DNS history, hosts file, COM and startup/task/service registrations | known indicators in supported network and persistence records; not a full persistence audit |
A Prefetch match (execution-record) does not identify the file's contents or full path;
an Amcache match (inventory-record) does not prove execution or that the file still
exists. Locked or unsupported records are gaps.
Antivirus status comes from Windows Security Center, including third-party products such as Bitdefender that register there. An active registered product puts an old Defender-off event in context; it does not mean protection is off now. Registration is not a health test, some enterprise products do not register, and unavailable status is a gap. A desktop app such as Slack is listed because its web records were checked, not because it is suspicious.
The default hash check covers .dll, .exe, .sys, .ocx, .cpl, .scr, .tmp,
.dat, .bin and .ax files up to 120 MiB in selected folders, skipping cache and
dependency directories. Computer checks can find published infrastructure or file traces;
they cannot tell whether a phone is infected.
macOS and Linux
The same browsers are checked at their default locations, plus common Snap and Flatpak
packages and Firefox's newer ~/.config/mozilla profile folder on Linux. On a Linux desktop
in another language, the translated Downloads, Desktop and Documents folders are found from
user-dirs.dirs. File fingerprints, separate browser cache locations and bounded saved-record
checks run without administrator access.
- Safari (macOS): history and profile databases, open and iCloud tabs, the URL cache, WebKit's tracking-prevention list, cookies, HSTS records, bookmarks, downloads, Top Sites and recently closed tabs.
- Startup configuration: on Linux, standard autostart
.desktopentries, systemd units and immediate.confoverrides, cron configuration and scheduled script directories; on macOS, standard LaunchAgent and LaunchDaemon property lists. A launch item's program is compared as an executable path and, by its file name, as a process name. - Shell and logs (both): standard shell startup files, saved Bash/Zsh/fish history
(including macOS Terminal's per-session history in
~/.zsh_sessions), the hosts file and readable current text system logs. Paths inside$( )and backticks are recognised. Large history and log files are limited to recent records; the omitted part is a gap.
These read saved configuration, not which jobs are enabled or ran. Network strings are references; exact known executable paths in supported launch configuration can be findings, with activation and execution unverified.
File checks also cover extensionless files, executables, native libraries and scripts in selected application, user and temporary folders (120 MiB limit). Windows-only live checks do not run here; copied Prefetch and Amcache files can still be selected in targeted mode, though compressed Prefetch needs Windows.
Desktop apps
Apps with a built-in Chromium browser are found by their folder contents under AppData (Windows), Application Support (macOS) or the user and Flatpak configuration folders (Linux), including apps whose own folder is a Chromium profile, such as Signal on macOS. The search has no fixed depth limit; it is bounded by folder count and time, and reaching that bound is reported as a gap.
Android
The tool reads a collection made with AndroidQF; it never talks to the phone itself. It checks:
- installed and running apps, their fingerprints and signing certificates;
- the install history, so an app that was installed and later removed still shows;
- system records, logs and crash records;
- supported, already decrypted intrusion logs: DNS lookups, TCP connection attempts and process-start events (a connection attempt does not prove success);
- links in SMS and MMS messages, from the SMS backup AndroidQF offers to take;
- apps installed outside an app store, with what they can do (read SMS, use the microphone, read notifications, resist uninstalling) and when they arrived;
- signs of a modified phone: unlocked bootloader, debug build, security protection off.
It recognises the collection's own traces (USB debugging, the debugging shell's permissions) and does not report them as suspicious.
iPhone
Local Finder, Apple Devices or iTunes backups (encrypted or not), extracted file systems and sysdiagnose archives. See Checking local iPhone evidence.
Indicators
About 12,400 published indicators from 29 sources: Amnesty International's Security Lab,
the Mobile Verification Toolkit project,
the Citizen Lab and Echap's stalkerware research, and a hand-curated set from Citizen Lab
reports (Candiru / DevilsTongue and Paragon's Graphite) with every line cited. The curated
set works offline; --update downloads the rest from a fixed list of official sources.
Install and run
You need Python 3.8 or newer (python.org; on Windows,
tick "Add python.exe to PATH" when installing). No administrator rights and no extra
packages. On macOS and Linux type python3 instead of python.
- Get the toolkit. On GitHub choose Code → Download ZIP and extract it, or:
git clone https://github.com/interplains/Zero-Breach-Toolkit.git - Open a terminal in the toolkit folder. Windows: open the extracted
folder (
Zero-Breach-Toolkit, orZero-Breach-Toolkit-mainfrom a ZIP), click the address bar, typepowershelland press Enter. macOS: open Terminal, typecd(with a space), drag the folder into the window and press Enter. Run every command below from this folder. - Recommended: download the latest indicator lists. This is optional and is the only
step that uses the internet; the checks themselves never do. Without it only a small
built-in set is used. Repeat it every few weeks.
python -X utf8 scan/zero-breach-toolkit.py --update - On a Mac, give Terminal Full Disk Access first (System Settings → Privacy & Security → Full Disk Access → add Terminal, then reopen it). Without it macOS blocks Safari's records and some folders, and the report lists them as not checked.
- Close your browsers and chat apps, then run the check. A menu opens; press Enter for
the standard check of this computer.
On Windows you can instead double-clickpython -X utf8 scan/zero-breach-toolkit.pyscan\run-scan.cmd. It saves the readable and JSON reports in afindingsfolder next to the toolkit.
Reports contain private details from your computer; keep them out of shared and synced folders. Useful options:
python -X utf8 scan/zero-breach-toolkit.py --quick # faster: skips file fingerprints
python -X utf8 scan/zero-breach-toolkit.py --phone "FOLDER" # a phone collection or backup
python -X utf8 scan/zero-breach-toolkit.py --json report.json # machine-readable report
python -X utf8 scan/zero-breach-toolkit.py --share-json summary.json # minimal summary for sharing
Put folder paths in quotes, especially if they contain spaces. On Linux or macOS,
sh scan/run-scan.sh takes the same options.
Verify what you run
The project is anonymous, so do not take its word for anything. Verification rests on what you can reproduce.
Running from source, as above, means every line the tool executes is in the clone: nothing is compiled and nothing is fetched in order to run.
The single-file zero-breach-toolkit.py attached to a release is generated from the same
source. Rebuild it from the release's tag and compare:
git checkout v0.1.13
python build/bundle.py
python -c "import hashlib; print(hashlib.sha256(open('dist/zero-breach-toolkit.py','rb').read()).hexdigest())"
For v0.1.13 the file is 973,579 bytes, SHA-256
bb0e6a7a36ee659c0494d02e9f7495d5fd4701f1ab7e57529e79925cb581ae15. The size and SHA-256
published with each release are authoritative. The build is deterministic, so a matching
rebuild means the published file contains that source and nothing else. Releases are also
GPG-signed; see docs/VERIFYING.md.
There is no signed Windows program, and none is planned while the project stays anonymous:
code-signing certificates require a named legal identity. An .exe you build yourself with
PyInstaller is unsigned, has no download reputation and is not byte-reproducible, so
SmartScreen will warn, some antivirus products will flag it, and the comparison above does
not apply. Running from source avoids all of that.
Checking an Android phone
On the phone, turn on Developer options (Settings → About phone → tap Build number seven times), then turn on USB debugging.
Connect the phone by USB and tap Allow when it asks about this computer.
Download and run AndroidQF on the computer. Answer its questions like this:
AndroidQF asks Answer Take a backup of the device? Only SMS Download copies of all apps or only non-system ones? Only non-system packages Remove copies of apps signed with a trusted certificate? No Take the Intrusion Logs? No, unless you turned on Intrusion Logging Hash files on the device? No (Yes also checks file fingerprints, but it is slow and can stop the collection on some phones) Browser history / Magisk modules? No On the phone, confirm the backup with Back up my data.
AndroidQF saves a
.zipnext to itself. Extract it.From the toolkit folder, check the extracted folder (keep the quotes):
python -X utf8 scan/zero-breach-toolkit.py --phone "PATH TO THE EXTRACTED FOLDER"Or run the tool with no options, choose A phone, and drag the folder into the window.
Turn USB debugging off again.
The collection holds private information about the phone. Keep it on your computer.
Use --phone-guide android for preparation steps and --phone FOLDER --preview to list
which artifacts are available. For an AES-encrypted backup.ab, add --backup-password;
the password is asked for privately at the terminal and never appears as an argument or in
a report. Age-encrypted acquisition archives must first be decrypted with the owner's
identity using the separate age tool; this scanner does not launch it.
Guided acquisition (experimental). --collect-android LOCAL_OUTPUT_FOLDER downloads
official AndroidQF v1.8.3, checks its pinned SHA-256, asks for the device owner's explicit
consent and runs the collector's interactive prompts. After a successful plaintext
acquisition it extracts the archive locally and checks the collection. Acquisition changes
phone state and saves private records; it is separate from read-only scanning.
This is the only point at which the tool runs a program it did not ship:
- the asset name and expected digest are fixed in the source;
- the file is fetched over HTTPS from the publisher's release, with redirects limited to an allow-list, and hashed while downloading;
- if the digest does not match, acquisition is refused and nothing is executed;
- the collector is written to a temporary directory and run directly, not through a shell,
with
ADB_,ANDROID_ADB_,LD_andDYLD_variables removed andPATHreset to the system directory, then deleted when the command finishes; - nothing is downloaded or run unless you invoke the command and confirm consent.
The pinned digest verifies the publisher's release bytes; it is not an independent audit of the collector. The publisher ships the Windows build unsigned, so a browser download shows the usual "not commonly downloaded" warning and SmartScreen prompts on first run. If you prefer, install AndroidQF yourself, follow the five steps above and skip this command.
--age-recipient-file PATH supplies public age1 recipients (private identity files are
refused). When encryption is requested, a plaintext result is refused. An encrypted result
must have a supported age envelope and no unexpected extra files, but these format checks
cannot authenticate it or verify the recipient. It is saved for separate decryption; the
command succeeds without producing a scan or an all-clear. After a failure, check the
reported folder: original or partial records are kept and may be unencrypted.
Checking local iPhone evidence
- Make a local backup with Finder (Mac) or Apple Devices / iTunes (Windows). Tick Encrypt local backup: encrypted backups include more of the records this tool checks.
- Find the backup folder (one per device, with
Manifest.plistinside): on a Mac~/Library/Application Support/MobileSync/Backup/, on Windows%USERPROFILE%\Apple\MobileSync\Backup\. - From the toolkit folder (keep the quotes; leave out
--backup-passwordif the backup is not encrypted, and the password is asked for privately):python -X utf8 scan/zero-breach-toolkit.py --phone "PATH TO THE BACKUP FOLDER" --backup-password
--phone-guide ios and --phone-guide android print these steps in the terminal.
Encrypted backups need the optional cryptography package already installed in your Python
environment; nothing is installed automatically. Install it from the toolkit folder with the
same command you start the check with: python3 -m pip install --require-hashes -r requirements-backups.txt on a Mac or Linux, python -m pip ... on Windows (every package
pinned by version and hash). If the check still says it needs cryptography, it was installed
for a different Python on the same computer. The supported version is cryptography 50.0.2, which needs Python 3.9 or
later. Intel Macs get 48.0.1, the last release published for them; its remaining advisories
concern certificate checking, which this tool does not use.
For evidence you already have, use --phone ROOT --ios-input filesystem for an extracted
file system, or --phone PATH --ios-input sysdiagnose for a directory or TAR/TAR.GZ archive.
Both are also in the phone menu. This does not acquire a device.
It reads messages (SMS, iMessage, WhatsApp), Safari and other browsers, data-usage processes, app records, permissions, calls, calendar, interactions, Shortcuts, configuration profiles, analytics and diagnostics (shutdown logs, crash and memory reports, running processes, installation logs). Local browser visits are separated from synced or imported ones; unknown origin stays a reference with a gap. Unusual paths alone are leads.
Committed SQLite WAL records, including encrypted backup sidecars, are validated and
replayed on temporary copies. JSON findings keep source hashes and record locators. While a
table's row index is readable, an unreadable message, visit or process row is skipped and
later rows are still checked; repeated gaps are grouped. Unsupported encodings or schemas,
damaged WALs, record caps, unavailable protection classes and encrypted Manifest.db WALs
are gaps. The test suite covers the table layouts
of iOS 15, 16, 17 and 18. See docs/IPHONE.md for exact support and limits.
Choosing the scope
--scan-type defaultuses the computer checks and file candidates supported on your platform.--scan-type fullalso reads desktop-app raw web caches and hashes all file extensions in the usual roots, including subdirectories normally skipped. It is broader, not a scan of every drive, account or artifact. The 120 MiB file limit remains.--scan-type targeted --target PATHreads only the selected files, directories, drives or browser profiles; repeat--targetfor several. Selected files are hashed whatever their extension, within the same size and access limits. Copied Prefetch/Amcache files inside the selection are also read. Live registry and log checks are outside this scope.--scan-type browserreads only this account's browser profiles and desktop apps with a built-in Chromium browser (history, cookies, site storage, caches and connection records) against every loaded list, including ad-campaign addresses. Large caches can take several minutes. Files, startup entries, DNS, registry and system events are not read.--previewprints the proposed scope without scanning. File hashing reports progress. Ctrl+C stops the scan and reports what was collected, with an incomplete-coverage gap.--extended-windowsadds existing Sysmon and Security process events. It does not enable logging or elevate privileges. If access is denied, a second run from an administrator terminal can read what the ordinary account could not.
On Windows, saved console and Explorer input is also read; it does not prove that anything
ran. Startup checks interpret recognisable batch commands, Internet Shortcut URLs and literal .lnk target and
argument metadata, without resolving or opening the target; anything they cannot interpret
is a gap. Related-record groups link the same indicator across artifacts with their dates
and original grades; they do not claim a causal attack sequence. Publisher validity,
platform and withdrawal labels are shown as context.
See the coverage table before relying on a particular check.
Start menu and follow-up
Running the tool in a terminal without choosing a check shows a menu. Enter starts the
standard check; 0 quits without scanning. The same menu offers a full check, a
browsers-only check, selected files or folders, or a phone collection. Scripts with
non-interactive input do not see it; --no-menu turns menus off.
The browsers entry also offers a test of whether your browser blocks ads. That test only works inside a browser, so the tool asks first and then opens the ArchiveGenocide test page in your default browser. The browser goes online for it; the tool does not. See PRIVACY.md.
After a menu-selected check you can inspect findings and references, review gaps and next
steps, save reports, or prepare a private evidence bundle. --post-menu offers the same
after a command-line scan. The report is shown before those choices. The Windows launcher
keeps prompts visible and saves both readable and JSON reports.
--report PATH saves the readable report, independently of --json and --share-json.
Reports never replace an existing file inside a selected evidence folder, a selected input
file, or the app data and app cache folders where desktop apps keep the records the scan
reads. Choose a new filename. No baseline snapshots are kept.
Private evidence handoff
--evidence-bundle PATH creates a new, unencrypted private ZIP with the full JSON
report, readable report, minimal sharing summary and an integrity manifest. Repeat
--evidence-file PATH to add original local files you choose. Report text never chooses
files to copy, and nothing is uploaded or sent to a helpline.
python scan/zero-breach-toolkit.py --scan-type targeted --target SUSPICIOUS_FILE --report report.txt --json report.json --evidence-bundle evidence.zip --evidence-file SUSPICIOUS_FILE
SUSPICIOUS_FILE is the path of one file; --evidence-file takes files, not folders.
The archive is previewed before it is created, never overwrites an existing file, and is limited to 128 originals of up to 64 MiB each and 256 MiB in total. It records SHA-256 hashes, tool version, scope, times and fingerprints of the indicator sets used. Hashes show later integrity, not authenticity to the original device. Originals are copied at export time and may differ from what was scanned; live databases may need their sidecar files selected too. Use the minimal summary for first contact, and share the full archive only through a secure route agreed with the recipient.
Reading the result
The report starts with a short summary: what was found, what it means, what to do, and what could not be checked. The evidence follows.
- Findings carry an evidence grade. "A known spyware file is on this machine" or "an app researchers name is on this phone" is strong. "A saved web page mentions the address" is weak, and is usually an article about the spyware. The grade, not the number of matches, decides what to do.
- Worth a look lists things the tool cannot judge on its own (a sideloaded app, a command that downloaded code, an antivirus exclusion), each with its usual harmless explanation. They are not findings.
- In time order lists every dated finding and item.
- What could not be checked. Read this part. A check that could not run has not cleared anything.
Exit codes for scripts:
| Code | Meaning |
|---|---|
0 |
no actionable matches and no recorded coverage gaps |
1 |
setup, argument or output error |
2 |
a match beyond a saved reference |
3 |
no actionable matches, but checks or indicator sources were incomplete |
4 |
the start menu was closed without scanning (no verdict or report) |
Reference-only matches stay visible and return 0 or 3, depending on gaps. No exit code
proves a device is safe.
What it cannot do
- It only finds published indicators. New or unpublished spyware will not be found.
- Spyware is often rebuilt for each target, and many traces expire within weeks.
- An Android check sees only what the collection contains; an iPhone check sees only supported artifacts in the local evidence supplied. Neither is a full phone examination.
- It does not replace a forensic examination by experts. If you are worried, ask for help.
Privacy
--update downloads indicator sources. The separate --collect-android command downloads
a pinned official collector after consent. Ordinary scans stay offline. Full reports can
contain usernames, profile names, file paths, browsing details, SMS senders and message
excerpts; keep them private. --share-json summary.json writes counts, scope labels, the
verdict and fixed advice, and leaves out artifact text, indicator values and dates. It is an
initial summary, not forensic evidence; review it before sharing. See PRIVACY.md.
For scripts and assistants
--describe prints, as JSON, every check the tool runs, what each reads and cannot see,
the exit codes and the rules for relaying a result. --json writes a machine-readable
report that marks the fields to relay to the person, the next steps that may be given, and
which fields hold untrusted text from the scanned machine. See
scan/CONTRACT.md.
A skill file is included for assistants that support
skills: add the skills/zero-breach-toolkit folder to the assistant's skill directory, or
have it read that file. It covers scope selection, encrypted-backup prompts, offline
operation, report interpretation and evidence privacy. Nothing is installed automatically.
Tested platforms
Windows, macOS, Linux, Android (AndroidQF collections) and iPhone (local backups). See docs/COVERAGE.md for what each check reads and its limits. Built-in readers share one registry for platform selection, coverage descriptions and the single-file build; see scan/READERS.md to add one.
Where the code is
There is no src folder; the code is under scan/:
scan/zero-breach-toolkit.py: the entry point you run.scan/zbtriage/: the scanner (indicator loading, the network block, reporting). The package keeps the project's earlier name so existing installs keep working.scan/zbtriage/modules/: one file per check (browsers, Windows records, macOS and Linux, Android, iPhone, file fingerprints).scan/tests/: the test suite.build/bundle.py: builds the single file attached to each release from this source (see Verify what you run).
Credits
Indicators are the work of Amnesty International's Security Lab, the Citizen Lab, the MVT project and Echap.
Licence
Code, including the generated scanner: Apache License 2.0 (LICENSE). The curated
indicator files in iocs/ and generated indicator exports in dist/: CC0 1.0, public
domain (iocs/LICENSE.md). Optional bundled research rules keep their own
licences in third_party/candiru. Indicator lists downloaded
by --update remain under their publishers' terms and are not part of this repository.

