malwagon
Scan a file for malware from your terminal, and get a scored verdict back
Automated malware analysis sandbox in one command. Upload a file and it detonates in an isolated virtual machine, observed agentless at the hypervisor layer, so there is no in-guest agent for a sample to find, unhook or disable. Windows kernel drivers get a dedicated BYOVD analysis module, and an AI layer explains the run in words. You get back a scored verdict, the indicators behind it, and an exit code your pipeline can gate on.
Install · Quick start · Why it is different · Screenshots · CI/CD · FAQ
📦 Install
pip install malwagon
That is the whole dependency list: none. The standard library makes the HTTPS request, so installing a malware analysis client does not widen your supply chain by four packages.
Works on Linux, macOS and Windows, Python 3.8+.
⚡ Quick start
# 1. get a free API key at https://malwagon.com (Settings -> API tokens)
export MALWAGON_API_KEY=mwg_...
# 2. scan anything
malwagon suspicious.exe
malwagon driver.sys
malwagon payload.elf
malwagon dropper.ps1
malwagon invoice.docm
$ malwagon suspicious.exe
uploading suspicious.exe (412.0 KB) to malwagon.com
scan 48213 queued
waiting for the sandbox, usually 90 to 300 seconds
queued 0s elapsed
running 12s elapsed
analyzing 2m 18s elapsed
MALICIOUS score 88/100
sha256 354fd5f5e4afc2280a19c8541fd4abe38bf8fb73efbeb3c2b0a4f2b1d9e0c7a1
report https://malwagon.com/s/48213
The sandbox is chosen from the file. A Windows binary detonates on Windows, an ELF or a pip package on the Linux sandbox, a kernel driver reaches the BYOVD analyzer. There is no flag to get wrong.
💻 Three ways to run it
| Installed command | malwagon suspicious.exe |
| Python module | python -m malwagon suspicious.exe |
| From a clone, no install | git clone https://github.com/Malwagon/malwagon-cli && cd malwagon-cliPYTHONPATH=src python -m malwagon suspicious.exe |
As a Python library
The client is importable, so a script can submit and poll without shelling out:
import os, time
from malwagon.client import Client
client = Client("https://malwagon.com", os.environ["MALWAGON_API_KEY"])
with open("suspicious.exe", "rb") as handle:
status, body, _ = client.submit_file(handle, "suspicious.exe", {"private": "true"})
scan_id = body["scan"]["scan_id"]
print("report:", client.report_url(scan_id))
while True:
status, body, _ = client.scan_status(scan_id)
scan = body["scan"]
if scan["terminal"]:
break
time.sleep(10)
print(scan["verdict"], scan["score"]) # -> malicious 88
Every response is bounded before it is parsed, TLS is verified, and redirects are never followed. See What this client will not do.
🔮 Why this sandbox is different
🧭 Hypervisor-level, agentless observation
Behaviour is recorded from outside the guest. The analysis is logged at the hypervisor layer rather than by a driver or a hooking DLL installed inside the virtual machine, so there is no in-guest agent for a sample to find, unhook or disable. Malware that checks for analysis tooling in its own process space finds an ordinary Windows desktop.
Real virtual machines on real hardware the operator runs. Not an emulator, not a container.
🛡 BYOVD and kernel driver analysis
A dedicated module for Windows kernel-mode PE images. Bring Your Own Vulnerable Driver is how modern ransomware turns off endpoint protection, and a driver is not an ordinary executable: the questions are which primitive it hands to user mode, which control codes reach it, and whether the world already knows it is abusable.
The kernel module returns the IOCTL dispatch surface, the privileged hardware access in the code (physical memory mapping, MSR access, arbitrary process termination), the signing and mitigation state, an ATT&CK mapping in kill-chain order, and generated Sigma rules as a downloadable bundle.
Every import, rule and hardware primitive is weighed against how common it is across a corpus of real signed drivers, so an ordinary call is not reported as a finding.
🧠 AI analysis on derived data only
The narrative layer explains the run in words, and never sees the sample. It receives a behaviour summary, the API call sequence, the indicator list and non-sensitive extracted strings, assembled locally by one module that copies named fields and drops everything else.
The raw sample is never sent to any model, and never leaves the analysis host. The AI layer reads what the platform already worked out; it does not do the working out.
📈 Four layers, one score
| Layer | What it contributes |
|---|---|
| Static | PE structure, packing and signing, capability detection, YARA, extracted strings |
| Dynamic | Process tree, file and registry activity, network, persistence, memory, screen recording |
| Threat intelligence | Reputation on hashes and derived indicators, open indicator feeds |
| AI | A written explanation of what the run did, from derived data only |
Each layer's contribution to the score is shown, so a verdict is auditable rather than an oracle.
🖼 Screenshots
The platform this client talks to
Drop a file in the browser, or send it from your shell with the same account. Seven submission modules: file, hash, command, URL, document, package and Windows kernel driver.
The report a scan produces
Score, the reasoning behind it, which layers ran and what each one moved.
⚙ Options
malwagon FILE [options]
| Option | Effect |
|---|---|
--json |
Print one JSON object and nothing else |
--no-wait |
Submit and exit immediately with the scan id |
--private |
Keep the report private (needs a plan that includes it) |
--internet |
Detonate with internet access (paid plans) |
--os KEY |
Force a sandbox image instead of letting the file decide |
--timeout-run N |
How long the sample runs inside the sandbox |
--no-dynamic |
Static analysis only, no detonation |
--quiet |
Drop the progress lines, keep the result |
--api-key-file PATH |
Read the key from a file |
--api-key-stdin |
Read the key from stdin |
--ca-bundle PATH |
Verify TLS against your own CA bundle |
malwagon --help lists every option.
Machine-readable output
$ malwagon sample.dll --json
{
"limitations": [],
"report_url": "https://malwagon.com/s/48213",
"scan_id": 48213,
"score": 88,
"sha256": "354fd5f5e4afc2280a19c8541fd4abe38bf8fb73efbeb3c2b0a4f2b1d9e0c7a1",
"size": 421888,
"status": "completed",
"verdict": "malicious",
"verdict_raw": null
}
Progress goes to stderr and the result to stdout, so malwagon sample.bin --json | jq works while you
still watch the wait.
🛠 Use it in CI/CD
The exit code is the verdict, so a build step can gate on it with no parsing:
| Code | Meaning |
|---|---|
0 |
Clean |
1 |
Malicious |
2 |
Error |
3 |
Suspicious |
malwagon dist/installer.exe --quiet || { echo "do not ship this"; exit 1; }
GitHub Actions
- name: Detonate the release artifact
env:
MALWAGON_API_KEY: ${{ secrets.MALWAGON_API_KEY }}
run: |
pip install malwagon
malwagon dist/installer.exe --json --quiet | tee scan.json
GitLab CI
malware-scan:
script:
- pip install malwagon
- malwagon dist/installer.exe --quiet
Useful for scanning build artifacts before release, third-party binaries before they reach a fleet, and attachments pulled out of a phishing report.
🔒 Authentication
The key comes from one of these, highest first:
--api-key-file PATH--api-key-stdinMALWAGON_API_KEYin the environment- the config file written by
malwagon login - an interactive prompt when stdin is a terminal
$ malwagon login
Malwagon API key for malwagon.com:
key accepted and saved to ~/.config/malwagon/config.json
The file is created mode 0600, and the client refuses to read it if the rest of the machine can.
There is deliberately no
--api-keyflag. A credential on the command line is visible to every process on the machine through the process list, and is written verbatim into your shell history and into CI job logs. The absence is a feature, and there is a test that keeps it absent.
🛡 What this client will not do
Everything here is enforced in code, and each one has a test:
- It will not disable TLS verification. There is no
--insecure, and there will not be one.--ca-bundleexists for a private deployment. - It will not follow redirects. A redirect is the standard way a bearer token is walked onto a host it was
not issued for. The client reports the
Locationinstead of chasing it. - It will not send your key to a host it was not stored for. Keys are bound per host, so
--api-url https://evil.examplecannot harvest a credential stored for somewhere else. - It will not send plain HTTP anywhere but loopback.
- It will not upload what you did not mean to upload. Symlinks, devices, pipes, directories, empty files and anything shaped like a private key or a credential file are refused unless you insist. Every check is made on the open file descriptor rather than on the path, so there is no window between the check and the read.
- It will not trust the server's text on your terminal. ANSI escapes, carriage returns, OSC 8 hyperlinks, clipboard writes and bidirectional overrides are stripped before anything is printed, and the verdict is read from a fixed vocabulary rather than echoed as the server spelled it.
- It will not parse an unbounded response. Bodies are capped before decoding, and the cap applies to the decompressed stream.
💰 Plans
A free Community key works and runs a network isolated scan: no internet egress from the sandbox, and no threat intelligence or AI layer on the report.
The client says which layers did not run, rather than leaving an empty section to be read as "the sample did nothing":
CLEAN score 10/100
report https://malwagon.com/s/48213
- threat intelligence lookups did not run
- the AI narrative did not run
a paid plan adds internet egress, threat intelligence and the
AI narrative to this report
| Community | Paid | |
|---|---|---|
| File, driver, document and script analysis | Yes | Yes |
| Hypervisor-level dynamic analysis | Yes | Yes |
| Live VNC while the sample runs | Yes | Yes |
| Internet egress from the sandbox | No | Yes |
| Threat intelligence enrichment | No | Yes |
| AI narrative | No | Yes |
| Private reports | No | Yes |
❓ FAQ
What is a malware analysis sandbox?
A malware analysis sandbox runs a suspicious file inside an isolated virtual machine and records what it actually does: the processes it starts, the files and registry keys it touches, the network it reaches and the persistence it installs. It answers "what does this do" rather than "does a signature match".
How do I scan a file for malware from the command line?
Install the client with pip install malwagon, set MALWAGON_API_KEY, then run malwagon suspicious.exe.
The command uploads the file, waits for the detonation, prints a scored verdict and a link to the full report,
and exits 1 if the verdict is malicious.
Is it free?
Yes, on the Community plan. Scans run network isolated and without the threat intelligence and AI layers. Paid plans add internet egress, reputation enrichment, the AI narrative and private reports.
Does the sample leave my machine?
Yes, it is uploaded to the analysis platform, because it has to be detonated there. Use --private on a plan
that includes private reports if the analysis should not be published to the public corpus.
What is agentless sandbox analysis?
Agentless means behaviour is recorded from outside the guest, at the hypervisor layer, rather than by software installed inside the virtual machine. There is no in-guest agent for a sample to detect, unhook or disable.
What is BYOVD?
Bring Your Own Vulnerable Driver: an attacker loads a legitimately signed but exploitable kernel driver to get kernel-level access, typically to disable endpoint protection. The kernel driver module analyses the driver's IOCTL dispatch surface and privileged hardware access to answer whether it hands that primitive out.
Can I use it in a CI pipeline?
Yes. The exit code is the verdict (0 clean, 1 malicious, 3 suspicious), so a build step gates on it with
no parsing. --json gives a machine-readable object on stdout while progress stays on stderr.
Does it work on Windows?
Yes. Linux, macOS and Windows, Python 3.8 and newer. The client uses no POSIX-only calls without a guard, and
the config file lives under %APPDATA% on Windows.
What file types can it analyse?
Windows executables and DLLs, Windows kernel drivers (.sys), Linux ELF binaries, Office documents and PDFs,
scripts (PowerShell, batch, VBS, JS, Python), archives, and pip packages. The platform types the sample by its
content, not by its extension.
🔗 Links
| Platform | https://malwagon.com |
| API reference | https://malwagon.com/docs/api |
| Command line docs | https://malwagon.com/docs/api#cli |
| Public scan corpus | https://malwagon.com/samples |
| PyPI package | https://pypi.org/project/malwagon/ |
📜 License
MIT. See LICENSE.
Keywords · malware analysis sandbox · automated malware analysis · dynamic analysis · static analysis · hypervisor-level monitoring · agentless sandbox · BYOVD · vulnerable driver analysis · kernel driver analysis · AI malware analysis · threat intelligence · IOC extraction · YARA · Sigma rules · MITRE ATT&CK · DFIR · malware sandbox CLI · malware scanning API · CI/CD malware scanning
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file malwagon-0.1.3.tar.gz.
File metadata
- Download URL: malwagon-0.1.3.tar.gz
- Upload date:
- Size: 478.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e43337f94f7c9cc52d059678adb259e51ffc3c9f6299746bc54503b86d34fd6
|
|
| MD5 |
c473682b8c1bcfe0e7d9b38e8f8866c2
|
|
| BLAKE2b-256 |
a84fd96fff75e46c2faac2f37af4a089ddb2191bd7d201199be5d6fbb26c577f
|
File details
Details for the file malwagon-0.1.3-py3-none-any.whl.
File metadata
- Download URL: malwagon-0.1.3-py3-none-any.whl
- Upload date:
- Size: 28.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
665bd3302a5cbc218b897dac02563859389d219dea7b4b818fd98686053d6b4f
|
|
| MD5 |
f92181ee8a9c4459c1e2c290c1c89cc8
|
|
| BLAKE2b-256 |
090d5215585a8101a8a44d752204fd0880f9dc9174e9d830f1a97865448e6e2d
|