Skip to main content

mwdb-cli

mwdb-cli

CLI and Python client covering the full MWDB Core API (all 122 operations)

PyPI Version Python Versions License SARIF TOON

GitHub Stars GitHub Issues Buy Me a Coffee


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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support the Project

If this project is useful in your workflows, you can support development:

Buy Me A Coffee

License

This project is licensed under the MIT license. See LICENSE.

Attribution


Built for practical malware triage and threat-intelligence automation

Metadata

Release files for mwdb-cli 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mwdb-cli 0.1.0
File Size Uploaded
mwdb_cli-0.1.0.tar.gz 41.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mwdb-cli 0.1.0
File Interpreter ABI Platform
mwdb_cli-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 75.5 kB

Release files / mwdb_cli-0.1.0.tar.gz

Download URL mwdb_cli-0.1.0.tar.gz
Size 41.6 kB
Tags Source
SHA-256 checksum
How to use checksums
870535c24aaa3bc2b80b18aaa9236677aa5d132aec0e7f643c2d21c7f83dbfe6
BLAKE2b-256 checksum
How to use checksums
b7c7cb483fabc40cbdb943b9ec29d9030567318f5f521197d39cff2dc5e05328
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release files / mwdb_cli-0.1.0-py3-none-any.whl

Download URL mwdb_cli-0.1.0-py3-none-any.whl
Size 33.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9bc617fac95285d935585860b3114d1fc5942795ed12ec5be39181fc5978a310
BLAKE2b-256 checksum
How to use checksums
3ce5e61f0a2bad35682b1ef9eb8627fa1501f4ae1037f9735ed5e4c04f4b2c37
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page