Skip to content

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 validation3.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 ​

EngineRoleHow it's installedRequired?
SemgrepAST + taint analysis; runs our malware rule pack on JS/TS/Python/PHPPython dependency (our direct dependency)Yes
GuardDogSupply-chain + package-metadata heuristics for npm/PyPIPython dependency (self-contained)Yes (deps mode)
malcontentRelease-diff and binary YARA detectionHomebrew (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) ​

sh
uv tool install malware-detector-py
# or
pipx install malware-detector-py

This pulls the orchestrator and its Python engine dependencies. To also enable --with-malcontent:

sh
brew install malcontent

From source ​

sh
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 ​

sh
# 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 check

Run 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 → pygit2 has no 3.14 wheel and fails to compile from source (no libgit2 build). GuardDog installs cleanly on 3.12 and 3.13 (verified; pygit2 1.18.2). Semgrep alone installs on 3.14, but the full stack does not — hence the <3.14 cap.
  • Install malcontent via Homebrew, not go install. go install github.com/chainguard-dev/malcontent/cmd/mal@latest fails because the yara-x cgo binding needs pkg-config, which isn't present by default. brew install malcontent uses 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-python and 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 on pygit2 anyway — 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).