scanything
Enables scanning GitHub repositories by downloading an archive pinned to a specific commit, branch, or tag, without cloning or running the code. Supports optional GITHUB_TOKEN for higher rate limits and private repository access.
Supports orchestrator mode using an OpenAI API key and model as the built-in AI analyst provider, including OpenAI-compatible servers for verdict explanations and tool-calling workflows.
Provides VirusTotal hash lookups via the vt_lookup tool and --vt options, enriching static scan results with antivirus engine detections without uploading files.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@scanything is ~/Downloads/Game_Setup.zip a virus? Defender says Wacatac"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Scanything
Scan any file for malware, with an AI that explains false positives.
Scanything dissects a .zip, .exe, .dll or a GitHub repository without ever running it, tells you whether it looks malicious, explains whether an antivirus alert is probably a false positive, and lets you chat about the result. It works inside Claude Code and Codex as an MCP server, or on its own with your API key.
🇮🇩 Bahasa Indonesia: docs/README.id.md
Quick start
pip install "scanything[pe] @ git+https://github.com/arielfikru/scanything"Then pick one:
scanything setup # use it from Claude Code / Codex (agent mode)export NETRA_API_KEY=... # or OPENROUTER_API_KEY / OPENAI_API_KEY
scanything ~/Downloads/file.zip # standalone AI analyst (orchestrator mode)No key and no agent? scanything file.zip --no-llm still gives the full static report.
Checking a repository before you clone it? scanything https://github.com/OWNER/REPO downloads the archive pinned to one commit and scans it in memory. Nothing is cloned, built or run.
Related MCP server: Malware-Sandbox-mcp
Two modes, one engine
🤖 Agent mode (MCP) | 🧠 Orchestrator mode | |
The AI is | your coding agent: Claude Code, Codex, any MCP client | Scanything's built-in analyst |
You need | the agent you already use | an API key: Netra, OpenRouter, OpenAI, or any OpenAI-compatible server |
Start with |
|
|
Good for | working in your editor or terminal agent | standalone use, scripts, CI |
Both modes use the same tools: scan_file, scan_github, get_report_section, search_strings, list_files, vt_lookup.
🤖 Agent mode: Claude Code & Codex
scanything setup # both agents
scanything setup claude # only Claude Code
scanything setup --dry-run # show what would happenAgent | MCP server | Skill |
Claude Code |
|
|
Codex |
|
|
No codex CLI on PATH? Add this to ~/.codex/config.toml:
[mcp_servers.scanything]
command = "/path/to/python"
args = ["-m", "scanything", "mcp"]Restart the agent and ask:
> is ~/Downloads/Game_Setup.zip a virus? Defender says WacatacThe agent calls scan_file, digs with search_strings and get_report_section, and answers with a verdict, the false-positive reasoning, the scan_id, and a next step.
🧠 Orchestrator mode: your own API key
Put one key in ~/.config/scanything/.env (template: .env.example) or export it, then:
$ scanything Game_Setup.zip --vt
== scanything: Game_Setup.zip ==
scan_id scn_9f2c41d0b7e3a8c5d1e6f402 · file_id (sha256) 5d41…c2a9 · ruleset rs_ace23f4945c8
Heuristic verdict: SUSPICIOUS (score 11, 3 file(s), static only)
# type size score name
0 zip 4.1 MB 4 Game_Setup.zip
1 pe 9.8 MB 7 └ Setup.exe
2 text 312 B 0 └ readme.txt
[*] Asking deepseek/deepseek-v4-flash-0731 via netra for a verdict...
↳ get_report_section(files[1].pe.suspicious_imports)
↳ search_strings({"file_index": 1, "pattern": "webhook|telegram"})
## Verdict: LIKELY FALSE POSITIVE (confidence 75%)
...
verdict_id vrd_3b8e… · scan_id scn_9f2c41d0b7e3a8c5d1e6f402
you> why does Defender call it Wacatac?Providers
| Key | Default model |
|
|
|
|
|
|
|
|
|
|
|
|
Without
--provider, Scanything usesLLM_PROVIDER, else the first key it finds (Netra → OpenRouter → OpenAI).--modelorLLM_MODELpicks any other model.scanything modelslists what your provider serves right now.Models without tool calling still work: Scanything falls back to plain chat, or pass
--no-tools.
Options
scanything setup.exe --vt # VirusTotal hash lookup (never uploads)
scanything locked.zip --password infected # encrypted archives
scanything file.exe --no-llm --json-out file.report.json # offline, no AI
scanything file.exe --no-chat --md-out verdict.md # CI / batch
scanything file.exe --provider openrouter --model anthropic/claude-sonnet-5.5 --lang en
scanything https://github.com/OWNER/REPO --no-llm # a repository, pinned to its latest commit
scanything github:OWNER/REPO@v1.2.0 # a branch, tag or commitFlag | Meaning |
| VirusTotal lookup of up to N hashes (needs |
| also run |
| YARA rule file or folder |
| zip password ( |
| static only, verdict only, model without function calling |
| override |
| save the full report, save the AI transcript |
GITHUB_TOKEN (optional) raises GitHub's rate limit and gives access to private repositories you can read.
In chat: /save [file.md], /exit. Config is read from ./.env, then ~/.config/scanything/.env.
What it checks
Layer | What Scanything looks at |
Archive | nested zips, zip-slip paths, zip bombs, password-protected executables, decoy names ( |
PE ( | sections and entropy, W+X sections, entry point, imports grouped by behaviour (injection, keylogging, download, anti-debug…), Authenticode presence and certificate names, version info, overlay including anti-scan padding, embedded PEs |
Toolchain DB | a Detect It Easy style database of about 40 signatures: installers (NSIS, Inno, WiX, 7-Zip SFX…), runtimes (PyInstaller, Nuitka, AutoIt, Go, Rust, .NET, Electron…), compilers (MSVC Rich header, MinGW, Delphi, VB6), packers (UPX, ASPack, MPRESS…), protectors (VMProtect, Themida, Enigma…) and .NET obfuscators, each with its false-positive note |
Strings & IOCs | URLs, IPs, registry keys, PowerShell cradles, LOLBins, shadow-copy deletion, Defender tampering, stealer paths, Discord/Telegram exfil, miners, ransom notes, EICAR, prompt-injection text |
Hidden strings | FLOSS-style recovery without emulation: x86 stack strings, single-byte XOR, base64 blobs and embedded PEs, PowerShell |
Source code | in repositories and any archive: npm install hooks, |
Repository | stars against owner-account age (star farming), new repository, fork, archived. Metadata never changes |
Optional engines | VirusTotal hash lookup, ClamAV, YARA, |
MITRE ATT&CK
Signals map to the ATT&CK technique they are typical of, like capa does, and the summary lists every technique with its evidence (T1490 Inhibit System Recovery <- #1 shadow_copy_delete). A mapping means "this evidence is typical of the technique", not proof that the file performs it.
How false positives are judged
Every signal carries an fp_note saying when it is harmless, and the AI weighs those against the evidence.
Usually a false positive | Usually real |
1–3 VirusTotal engines, all generic/ML names ( | named malware families across many engines |
PyInstaller, Nuitka, AutoIt or Go binaries | injection + network + persistence together |
UPX packing, NSIS or Inno Setup installers | stealer paths plus an exfil channel |
signed by a known publisher (verified with | decoy extensions, padded overlays, encrypted archives hiding an exe |
Scan IDs
Every result gets IDs, like the hash-based IDs of malware scanning platforms.
ID | Deterministic? | Computed from |
| ✅ always | SHA-256 of the file (same as VirusTotal) |
| ✅ same file + name + Scanything version + ruleset | hash of the static analysis |
| ✅ | hash of every detection rule table |
| ❌ one per AI answer | hash of |
scan_id ignores volatile data (timestamps, local path, VirusTotal/ClamAV results), so anyone scanning the same file with the same version gets the same id. It also seals the report:
from scanything.ids import scan_id_of
assert scan_id_of(report) == report["ids"]["scan_id"] # fails if the JSON was editedWith --json-out, the report also holds verdict = {verdict_id, scan_id, label, confidence, provider, model, created}.
Try it safely
python scripts/make-test-samples.py # harmless samples in ./samples (gitignored)
scanything samples/eicar.zip # EICAR: every AV flags it, it does nothing
scanything samples/stealer_lookalike.exeThe samples are one-instruction PE stubs with malware-like strings, plus the standard EICAR test file. None of them does anything when run.
Highly recommended: Netra Runtime
We highly recommend Netra Runtime for orchestrator mode: fast inference, an OpenAI-compatible API, and DeepSeek V4 Flash 0731 handles the tool calling the analyst relies on. It is the first provider Scanything looks for, so NETRA_API_KEY is all you need. Save a key from your clipboard with scripts/save-netra-key (macOS).
The recommendation appears in this README, as a CLI hint when no key is set, as a one-line footer when Netra produced the verdict, and in the agent instructions only if you ask which provider to use. It never appears inside a verdict or affects how files are judged. SCANYTHING_NO_RECOMMEND=1 hides it.
How it works
file or GitHub repo ──► scanner (recursive, in memory, never executed)
├─ static: type, hashes, entropy, strings/IOCs, PE, toolchain DB, decoded strings, code rules
├─ archive: entries, passwords, bombs, nested files
└─ engines (optional): VirusTotal, ClamAV, YARA, osslsigncode
──► report: signals + fp_notes + heuristic score + file_id / scan_id
──► tools: scan_file · scan_github · get_report_section · search_strings · list_files · vt_lookup
├─ MCP server ──► Claude Code / Codex / any MCP client (agent mode)
└─ built-in analyst ──► Netra / OpenRouter / OpenAI (orchestrator mode)Module | Role |
| file type, string and IOC rules, PE parser |
| toolchain signature DB / hidden-string recovery |
| GitHub download pinned to a commit, source code and metadata rules |
| signal → MITRE ATT&CK mapping |
| recursive scan, zip handling, YARA, signature verification |
| VirusTotal and ClamAV |
|
|
| report, compact AI view, terminal summary / deterministic ids |
| OpenAI-compatible client, tool loop, chat / provider presets |
| MCP server (stdio) / |
| agent skill |
Content from a scanned file is untrusted: both the MCP instructions and the analyst prompt say so, and text that tries to steer an AI is flagged as a prompt_injection signal.
Limits
Static analysis can never prove a file is safe. When in doubt, use a sandbox (ANY.RUN, Hybrid Analysis, Tria.ge) or the vendor's published hash.
No machine-learning score: there is no trained, openly licensed model small enough for a stdlib-only core, and an unexplained number would undercut the false-positive reasoning. VirusTotal results already include vendors' ML engines.
Hidden-string recovery is pattern based, not emulation: multi-byte XOR, RC4 and runtime-built strings are not recovered.
Repositories: up to 10,000 archive entries and 3,000 analyzed files, 512 MiB archive. Only what is in the repository is scanned, not the dependencies it pulls at install time.
7z, RAR and ISO are detected but not unpacked yet: extract them without running anything, then scan the contents.
Authenticode is only verified when
osslsigncodeis installed; otherwise Scanything reports its presence and certificate names.The AI can be wrong. Treat its verdict as a second opinion with cited evidence.
Development
git clone https://github.com/arielfikru/scanything && cd scanything
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/pyflakes scanything tests && .venv/bin/pytest -qSee CONTRIBUTING.md, AGENTS.md and SECURITY.md. Never commit live malware.
License
MIT, see LICENSE.
Available Tools
5 toolsget_report_sectionARead-only
Return part of the FULL JSON report by path, e.g. 'files[1].pe.imports', 'files[0].archive.entries', 'files[2].iocs', 'engines'. Empty path lists top-level keys.
Inputs: path (required), scan_id (required).
list_filesBRead-only
List all analyzed files with index, parent, type, size, score and sha256.
Inputs: scan_id (required).
scan_fileARead-only
Statically scan a file on disk (zip, exe, dll, script, anything) for malware and false-positive indicators. The file is never executed. Returns a compact report and a deterministic scan_id for follow-up tools.
Inputs: path (required), password, virustotal.
scan_githubARead-only
Download a public GitHub repository (zip archive pinned to one commit) and scan it statically: install hooks, obfuscated exec/eval, auto-run VS Code tasks, risky workflows, binaries inside, plus repository metadata. Nothing is cloned, built or run. Returns the same compact report and scan_id as scan_file.
Inputs: repo (required), virustotal.
search_stringsBRead-only
Case-insensitive regex search over printable strings extracted from one file.
Inputs: pattern (required), scan_id (required), file_index (required), limit.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 5 tools
Each tool has a clearly distinct role: scan a local file, scan a GitHub repo, retrieve a report section, search strings in one file, or list analyzed files. The two scan tools differ by input source and the follow-up tools target different inspection needs.
All tool names follow a consistent snake_case verb_noun pattern: scan_file, scan_github, get_report_section, search_strings, list_files. There are no mixed conventions or vague names.
Five tools is well-scoped for a static malware scanning service. There are two entry-point scan tools and three focused follow-up tools, with no obvious redundancy.
The surface covers scanning local files and GitHub repos, then inspecting results via file listing, report sections, and string search. Minor gaps exist, such as no explicit full-report retrieval or batch scanning, but core workflows are covered.
Maintenance
Related MCP Connectors
Scan AI agent skills, MCP server packages and MCP configs before you install them. Static analysis.
Checks AI-written code for leaked keys and made-up packages, on your machine. Never uploads code.
Security scanner for AI agents: prompt injection, leaked secrets, PII, and SSRF-risk URL detection.
Zero-config MCP security scanner for AI-generated apps. 25K+ vulnerability patterns.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceIntegrates 15+ static application security testing tools (Semgrep, Bandit, TruffleHog, etc.) with Claude Code AI, enabling automated vulnerability scanning and security analysis through natural language commands. Supports cross-platform operation with remote execution on dedicated security VMs.6MIT
- AlicenseAqualityCmaintenanceEnables assistants to analyze files and URLs for malware by integrating with security services like VirusTotal and ANY.RUN, returning threat reports.20MIT
- AlicenseNot gradedqualityCmaintenanceEnables scanning of AI agent code for security vulnerabilities such as prompt injection, tool abuse, and data exfiltration, directly from MCP-compatible clients like Claude Code.41 PyPI3LGPL 3.0
- AlicenseAqualityDmaintenanceEnables scanning of Claude Code skills, plugins, or MCP servers for malware before installation via static analysis.114 npmMIT