mwdb-cli
CLI and Python client covering the full MWDB Core API (all 122 operations)
Overview
mwdb-cli is a Python toolkit to work with MWDB Core (CERT.pl's malware database) from the command line or as a library. It covers every operation of the MWDB Core API — all 122 operations of spec 2.18.0 — with an async-native core, a synchronous facade, and machine-readable outputs including JSON, TOON and SARIF 2.1.0.
Key Features
| Feature | Description |
|---|---|
| Full API coverage | All 122 operations of MWDB Core 2.18.0, enforced by a spec regression test |
| Async + sync | Async-native client with a synchronous facade over the same implementation |
| Multi-format output | Rich tables, JSON, TOON, and SARIF 2.1.0 |
| Typed models | Dataclasses for files, configs, blobs and objects, keeping the full raw payload |
| Concurrent transfers | Bulk downloads with --jobs; blocking I/O offloaded to threads |
| Resilient transport | Automatic retry/backoff on 429/5xx and typed exceptions |
| CLI + Library | Use the mwdb command or import the Python package |
| 100% tested | Live tests against a real MWDB instance (no mocks), 100% coverage |
Supported Outputs
Object data JSON, TOON
Listings Rich tables, JSON, TOON, SARIF 2.1.0
Findings SARIF 2.1.0 (samples/objects as results)
Downloads Streamed files, concurrent (--jobs)
Installation
From PyPI (Recommended)
pip install mwdb-cli
From Source
git clone https://github.com/seifreed/mwdb-cli.git
cd mwdb-cli
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e . --group dev
Configuration
Settings resolve in order: CLI flags / constructor arguments → environment → config file → defaults.
export MWDB_URL="https://mwdb.cert.pl" # default
export MWDB_API_KEY="<your API key>"
or ~/.mwdb.toml:
[mwdb]
url = "https://mwdb.cert.pl"
api_key = "<your API key>"
Quick Start
# Ping the server
mwdb server ping
# List the ten most recent samples
mwdb file list --count 10
# Export search results as a SARIF 2.1.0 document
mwdb --format sarif search 'tag:emotet' > results.sarif
Usage
Command Line Interface
mwdb file get <sha256>
mwdb search 'tag:emotet AND file.size:[* TO 500000]'
mwdb file download <sha256> <sha256> ... --jobs 8 -o samples/
mwdb file download <sha256> --zip -o samples/
mwdb file upload sample.bin --tags my-tag --share-3rd-party false
mwdb tag add <sha256> my-tag
mwdb comment add <sha256> "packed with UPX"
mwdb config list --query 'config.family:emotet'
mwdb attribute add <sha256> source '{"feed": "honeypot"}'
mwdb --json file get <sha256> | jq .tags
Every API area has a command group:
file, config, blob, object, tag, comment, attribute, share,
relation, karton, quick-query, auth, user, api-key, group,
attribute-def, metakey, oauth, remote, server, plus top-level
search. Run mwdb <group> --help for the operations in each group.
Global options: --url, --api-key, --config, --format, --json.
Output Formats
--format selects how results are rendered (default: table):
| Option | Description |
|---|---|
--format table |
Human-readable rich tables (default) |
--format json |
Pretty JSON (--json is a backward-compatible alias) |
--format toon |
TOON: compact, token-efficient for LLMs |
--format sarif |
SARIF 2.1.0 findings |
mwdb --format toon file list # tabular TOON block
mwdb --format sarif file list # SARIF 2.1.0 document
mwdb --json file get <sha256> # same as --format json
SARIF is a findings schema, so it is available only for commands that
return samples or objects (file/config/blob/object list and get,
and search). Each object becomes one SARIF result (artifact = sha256,
ruleId = family/tag/type). Other commands report
SARIF output is not available for this command.
Python Library
Async
import asyncio
from pathlib import Path
from mwdb_cli import AsyncMwdbClient
async def main() -> None:
async with AsyncMwdbClient() as client: # settings from env/config file
async for sample in client.files.iterate(query="tag:emotet"):
print(sample.sha256, sample.file_name)
await client.files.download(sample.id, Path(sample.id))
break
asyncio.run(main())
Sync
from mwdb_cli import MwdbClient
with MwdbClient() as client: # same API surface, runs the async core internally
for sample in client.files.iterate(query="tag:emotet", chunk_size=50):
print(sample.sha256)
stats = client.configs.stats()
Concurrent bulk work
from pathlib import Path
from mwdb_cli import AsyncMwdbClient
from mwdb_cli.bulk import run_limited
async def bulk(client: AsyncMwdbClient) -> None:
hashes = [f.id async for f in client.files.iterate(query="tag:emotet")]
await run_limited(
[lambda h=h: client.files.download(h, Path(h)) for h in hashes],
limit=8,
)
TOON and SARIF encoders
from mwdb_cli import sarif, toon, MwdbClient
with MwdbClient() as client:
samples = client.files.list(query="tag:emotet", count=20)
print(toon.encode([s.raw for s in samples])) # compact TOON
if sarif.is_supported(samples):
document = sarif.encode(samples) # SARIF 2.1.0 dict
Errors are typed: AuthError, ForbiddenError, NotFoundError,
ValidationError, ConflictError, RateLimitError, ServerError,
MwdbConnectionError — all subclasses of MwdbError. Rate-limited and
transient 5xx responses are retried automatically with backoff.
Development
Quality gates (all must pass clean, with no suppressions):
black --check . && ruff check . && mypy .
bandit -r -c pyproject.toml . && pip-audit
MWDB_API_KEY=<key> pytest # live suite, 100% coverage enforced
The test suite talks to a real MWDB instance (no mocks): read operations run for real; mutating admin operations are exercised against requests the server rejects (missing capability → 403, nonexistent object → 404), so production data is never modified. Transport edge cases (retries, malformed bodies) run against a real in-process HTTP server.
Requirements
- Python 3.14+
- Runtime dependencies:
httpx,click,rich - See pyproject.toml for the full list
Contributing
Contributions are welcome.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support the Project
If this project is useful in your workflows, you can support development:
License
This project is licensed under the MIT license. See LICENSE.
Attribution
- Author: Marc Rivero López | @seifreed
- Repository: github.com/seifreed/mwdb-cli
Built for practical malware triage and threat-intelligence automation
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 mwdb_cli-0.1.0.tar.gz.
File metadata
- Download URL: mwdb_cli-0.1.0.tar.gz
- Upload date:
- Size: 41.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
870535c24aaa3bc2b80b18aaa9236677aa5d132aec0e7f643c2d21c7f83dbfe6
|
|
| MD5 |
6a6b54c8e9951632ec0fe8c449ea823e
|
|
| BLAKE2b-256 |
b7c7cb483fabc40cbdb943b9ec29d9030567318f5f521197d39cff2dc5e05328
|
Provenance
The following attestation bundles were made for mwdb_cli-0.1.0.tar.gz:
Publisher:
publish.yml on seifreed/mwdb-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mwdb_cli-0.1.0.tar.gz -
Subject digest:
870535c24aaa3bc2b80b18aaa9236677aa5d132aec0e7f643c2d21c7f83dbfe6 - Sigstore transparency entry: 2497844156
- Sigstore integration time:
-
Permalink:
seifreed/mwdb-cli@50459c660b59b5e1979843b8c0573f2e87c00be8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/seifreed
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@50459c660b59b5e1979843b8c0573f2e87c00be8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mwdb_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mwdb_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9bc617fac95285d935585860b3114d1fc5942795ed12ec5be39181fc5978a310
|
|
| MD5 |
b49941c38b63639ad51ca3708487f4b2
|
|
| BLAKE2b-256 |
3ce5e61f0a2bad35682b1ef9eb8627fa1501f4ae1037f9735ed5e4c04f4b2c37
|
Provenance
The following attestation bundles were made for mwdb_cli-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on seifreed/mwdb-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mwdb_cli-0.1.0-py3-none-any.whl -
Subject digest:
9bc617fac95285d935585860b3114d1fc5942795ed12ec5be39181fc5978a310 - Sigstore transparency entry: 2497844172
- Sigstore integration time:
-
Permalink:
seifreed/mwdb-cli@50459c660b59b5e1979843b8c0573f2e87c00be8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/seifreed
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@50459c660b59b5e1979843b8c0573f2e87c00be8 -
Trigger Event:
release
-
Statement type: