
Introducing GuardDog 3.0: new YARA rules engine, risk scoring, and sandboxing
Datadog Security Labs details GuardDog 3.0, an open-source PyPI/npm/Go malicious-package scanner, which replaces its Semgrep-based detections with a YARA rules engine (via yara-python) for better performance at scale, adds a risk-scoring engine that correlates capability rules (e.g., network access) with threat-indicator rules (e.g., suspicious domains, deobfuscation routines) into a 0-10 risk score, and sandboxes the scanning process itself with nono-py to contain vulnerabilities in GuardDog's own extraction/scanning code. The post also covers their continuous evaluation pipeline, which clusters their 27k+ open malicious-package dataset with TLSH before sampling to compute precision, recall, F1, and MCC nightly in CI.
What it is
Datadog's GuardDog 3.0, an open-source CLI for scanning PyPI, npm, and Go packages for malicious code. This release replaces the Semgrep-based scanning of prior versions with a YARA engine (via yara-python), adds a two-layer risk-scoring model, and wraps scanning in a sandbox.
How it works
The summary names the three changes; the page gives the reasoning and mechanism the summary can't.
Why the engine changed: Semgrep was dropped not for features but for scale problems — high memory on large files, slow on multi-file packages (it spawns a process per scan), built as a CLI rather than a library, and rules that overfit specific malware samples. YARA runs natively through a CPython extension.
Risk model: GuardDog 2.0 emitted one finding per rule match with no prioritization or correlation, treating heuristics (weak signals) as if definitive. 3.0 runs two YARA rule types and combines them:
- Capability rules — what a package can do, not inherently malicious (e.g.
capability.network.outbound,capability.runtime.clipboard). - Threat-indicator rules — suspicious domain extensions, sensitive filenames, deobfuscation routines, sensitive env-var names.
It correlates the two to find code that both can and appears to be performing malicious actions, mapped across the attack lifecycle (unusual metadata → execution vector → credential access → exfiltration → second-stage → persistence), then emits a risk score on a scale of 10.
flowchart LR C[Capability rules<br/>what it CAN do] --> X[Correlate] T[Threat-indicator rules<br/>suspicious signals] --> X X --> S[Risk score /10]
Sandbox: Scanning (both package extraction and YARA scanning) runs inside the Nono sandbox via nono-py, with restricted network and filesystem access by default and no prerequisites. This exists because past reported vulnerabilities let a crafted package achieve arbitrary file read/write or RCE on the scanning host. Once applied, the sandbox cannot be disabled from within the process.
What to do
If Nono isn't supported in your environment, disable sandboxing with:
--no-sandboxNote the tradeoff: disabling it removes the defense-in-depth against a malicious package exploiting a GuardDog bug to compromise the scanning machine.
Caveats
The page's authors frame the risk score explicitly as a probability estimate that a package is malicious, built on heuristics — signals, not proof. The truncated fetched text cuts off before the "Quantifying risk" scoring factors and the performance-evaluation section, so the exact weighting inputs aren't stated here.
Organisations named here
- Shai-Hulud
- TLSH
Technologies named here
- GuardDog
- npm
- PyPI
- Semgrep
- YARA
- Golang modules
- Nono / nono-py
- React
- TLSH algorithm
- litellm 1.82.7
- Datadog malicious-software-packages-dataset
- Python
- Go
Techniques named here
- Dependency confusion
- Typosquatting / name resemblance
- Metadata mismatch backdooring
- Execution vector via install scripts
- Credential access
- Exfiltration
- Second-stage payload retrieval
- Persistence
- Capability + threat indicator correlation
- Static Analysis
Threat actors named here
- Shai-Hulud
- compromised_lib
Related in Supply Chain


