Installation & Dependencies
malware-detector is a thin orchestrator: it drives existing detection engines and normalizes their output. This page covers the supported Python versions, how to install the tool and its engine dependencies, and the install gotchas we hit while validating the approach (so you don't have to rediscover them).
Supported Python versions
| Version | |
|---|---|
| Supported range | >=3.10, <3.14 |
| Recommended (dev + CI) | 3.13 |
| Verified in validation | 3.12 and 3.13 |
Why the <3.14 upper bound: GuardDog depends on pygit2, which currently ships no wheel for Python 3.14 and fails to build from source. The whole engine stack therefore cannot be installed on 3.14 (see Install findings below). Use 3.13.
Engines this tool depends on
| Engine | Role | How it's installed | Required? |
|---|---|---|---|
| Semgrep | AST + taint analysis; runs our malware rule pack on JS/TS/Python/PHP | Python dependency (our direct dependency) | Yes |
| GuardDog | Supply-chain + package-metadata heuristics for npm/PyPI | Python dependency (self-contained) | Yes (deps mode) |
| malcontent | Release-diff and binary YARA detection | Homebrew (Go binary) | Optional (scan --with-malcontent) |
Both Semgrep and GuardDog are Python packages, so a single pip/pipx/uv install pulls the entire core engine stack — there is nothing to install separately. (Note: GuardDog 3.x ships its own analysis engine plus YARA and no longer depends on Semgrep, so we declare Semgrep ourselves — it is what runs our rule pack.) Only malcontent, a standalone Go binary, is installed out-of-band, and only for the optional scan --with-malcontent.
Install the tool
End users (one command)
uv tool install malware-detector-py
# or
pipx install malware-detector-pyThis pulls the orchestrator and its Python engine dependencies. To also enable --with-malcontent:
brew install malcontentFrom source
git clone https://github.com/benzid-wael/malware-detector
cd malware-detector
make install # uv sync: .venv from uv.lock, editable install + dev tools (ruff, mypy, pytest)Development setup
# 1. Install uv (https://docs.astral.sh/uv/). It reads .python-version and fetches
# Python 3.13 if you don't have it.
brew install uv # or: curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. Create .venv with the exact versions pinned in uv.lock
make install
# 3. Run the full quality gate (format check + lint + type-check + tests)
make checkRun any tool inside the environment with uv run (for example uv run malware-detector scan .), or source .venv/bin/activate.
All dependency versions, including transitive ones, are pinned with hashes in uv.lock, which is committed. CI, the Docker image and make targets install with --locked, so they fail instead of silently resolving something new. After changing dependencies in pyproject.toml, run make lock and commit the updated uv.lock. Dependabot proposes weekly updates to it.
uv.lock only pins the development, CI and Docker environments. People who install from PyPI resolve versions from the ranges in pyproject.toml.
Install findings
These are the concrete gotchas found while validating the engines. Recorded here so they don't get rediscovered.
- Python 3.14 is not usable yet. GuardDog →
pygit2has no 3.14 wheel and fails to compile from source (no libgit2 build). GuardDog installs cleanly on 3.12 and 3.13 (verified;pygit21.18.2). Semgrep alone installs on 3.14, but the full stack does not — hence the<3.14cap. - Install malcontent via Homebrew, not
go install.go install github.com/chainguard-dev/malcontent/cmd/mal@latestfails because theyara-xcgo binding needspkg-config, which isn't present by default.brew install malcontentuses a prebuilt bottle (v1.24.2) and just works. This is one reason malcontent stays optional/out-of-band rather than a hard dependency. - GuardDog 3.x dropped Semgrep. GuardDog 2.x used Semgrep; 3.x (3.0.2, what installs on supported Pythons) replaced it with its own engine (
nono-py) +yara-pythonand no longer depends on Semgrep. We therefore declare Semgrep as our own direct dependency — it is what runs our rule pack. (On Python 3.14, pip silently backtracks to the old Semgrep-based GuardDog 2.10.0, then fails onpygit2anyway — another reason to stay<3.14.) - One command, by design. End-user install is still a single
uv tool install/pipx install: our package depends on both Semgrep and GuardDog, and pip resolves both at once. Users never install engines separately (except optional malcontent).