# vet: scanning lockfiles, workflows and agent configs for supply chain risk

> vet is a Go tool that reads the lockfiles, manifests, CI workflows and AI agent configs of a project and reports malicious packages, known vulnerabilities and risky workflow patterns, with policy as code in CEL deciding when a scan fails. It never installs or runs the dependencies it inspects, and the v2 branch is in alpha while v1 remains the latest release.

**safedep/vet** — Protect against malicious open source packages 🤖

- Repository: https://github.com/safedep/vet
- Website: https://safedep.io
- Stars: 1,125 · Forks: 115
- Language: Go
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/safedep-vet

## The threat model in one line

The Why vet section is the shortest and the most important part of the README, and it reads like a threat model. Your dependencies, your GitHub Actions workflows and your AI agent configs run code that you did not write, and vet finds the risk in them. The tagline at the top of the page frames the same idea from the other side, to find malicious packages, vulnerabilities and risky CI workflows before they reach production. So the scope is three things a developer pulls in but does not author, the packages, the workflows, and the agent configuration files. That third category is new and is the reason the tool is not just a software composition analysis tool, and the two AI features, endpoint audit and agent mode, exist because the same reasoning applies to the tools an agent runtime loads.

## What it checks, and the two claims worth checking for yourself

The feature list is six items, and they divide into a detection half and a decision half. Malicious packages are checked against SafeDep Threat Intel, which analyzes new package versions when the registries publish them. Known vulnerabilities come with the fixed version to upgrade to. Risky workflows cover dangerous triggers, template injection, exposed secrets and actions with no pinned commit SHA. Lockfile tampering and fresh versions cover entries from an untrusted registry and versions inside the cooldown window. Policy as code is rules in CEL that decide when a scan fails, and you can test a rule on a saved scan. And AI and crypto inventory lists the AI libraries and crypto algorithms your code calls, writing a CycloneDX xBOM and CBOM. Two claims in that list are worth holding loosely, since the README states that vet needs no account and sends no source code, while the go.mod includes a posthog-go dependency and the module path is safedep/vet/v2, so the intelligence is a hosted service.

## What it scans, and what it explicitly does not do

The scan targets table is wider than the lockfile idea suggests. A directory is the default, and you can point at a subdirectory. A git repository can be scanned by URL. A container image can be scanned, either as an OCI reference such as oci://alpine:3.20 or as an image tarball. An SBOM in CycloneDX or SPDX form can be scanned. A single package can be scanned with a package URL such as pkg:npm/express@4.19.2. And there is a separate command, vet endpoint audit, which lists the tools on the machine. The lockfiles and manifests it reads cover npm, PyPI, Go, Maven, Gradle, Cargo, RubyGems, NuGet, Packagist, Pub and more, and it also reads the GitHub Actions workflows and the AI agent configs of the target. The sentence that matters is the last one in that paragraph, that it does not install or run any of them.

```bash
vet scan
vet scan ./service
vet scan https://github.com/safedep/vet
vet scan oci://alpine:3.20
vet scan sbom.cdx.json
vet scan pkg:npm/express@4.19.2
vet endpoint audit
```

## Policy as code, and the suppression with an expiry date

A policy decides when a scan fails, and the file is a YAML document with a version, a list of rules and a list of suppressions. Each rule has an id, an optional description, a when expression and an action, and the expressions are CEL predicates over the finding and the package. The examples show a rule that fails on a finding whose family is malware, a rule that fails on the dangerous-trigger and template-injection control ids, a rule that fails on a critical vulnerability, and a rule that fails when a pull request adds a package version less than fourteen days old. Suppressions are keyed by a package URL and carry a reason and an expires date, and after the expiry date the suppression no longer hides the finding. That expiry field is the detail worth copying, because a suppression without an end date is a permanent exemption that nobody reviews.

```yaml
version: 2
rules:
  - id: no-malware
    description: A malicious or suspicious package fails the build.
    when: finding.family == "malware"
    action: fail
  - id: no-workflow-injection
    when: finding.control_id in ["dangerous-trigger", "template-injection"]
    action: fail
  - id: new-dependency-age
    when: package.change == "ADDED" && has(package.days_since_publish) && package.days_since_publish < 14
    action: fail
suppressions:
  - purl: pkg:npm/lodash@4.17.20
    reason: The upgrade to 4.18.1 is in pull request 42.
    expires: 2026-12-31
```

## Testing a policy on a saved scan before you apply it

The workflow for adopting a policy is two commands, and the first one is the one that makes the second safe. You test the policy on the last scan with no new scan, using vet report show last with the policy file, and then you apply it to a pull request with vet scan with the base-ref flag and the policy file. So a policy can be evaluated against the history of your project before it starts failing builds, which is the difference between tuning a gate and being surprised by it. The base-ref option also serves a second purpose, since it reports only the packages and workflows that a change adds, so a pull request that touches one dependency is not reported against the entire existing dependency set. There is also a SARIF export, vet report show with the report option, which writes SARIF from the saved scan with no new scan, for GitHub code scanning.

```bash
vet report show last --policy vet-policy.yml
vet scan --base-ref origin/main --policy vet-policy.yml

vet scan --fail-on high
vet scan --base-ref origin/main --fail-on high
vet report show --report sarif=vet.sarif
```

## Four install channels, and the alpha state of the v2 branch

The install table lists four channels, and the caveat above it is the important part. This branch is vet v2, in alpha, while vet v1 is on main and stays the latest release, and the v2.0.0 release notes map each v1 command and flag to v2. The channels are Homebrew with a cask from the safedep tap, mise, Go with go install of the cmd/vet package, and a container run against ghcr.io/safedep/vet. The mise channel installs a release one day after its publication, and the install documentation has the command for the newest build, the release binaries and the build attestations. The release tags on the v2 branch are dated alphas, v2.0.0-alpha builds from consecutive days in October 2026, so the v2 line is being cut continuously and none of it is a stable release yet.

```bash
brew install --cask safedep/tap/vet@edge
mise use -g 'github:safedep/vet[prerelease=true]@2'
go install github.com/safedep/vet/v2/cmd/vet@latest
docker run --rm -v "$PWD:/src" -w /src ghcr.io/safedep/vet:v2-latest scan
```

## The AI-facing parts: agent mode, endpoint audit and the xBOM

Three features are aimed at the AI tooling in a development environment rather than at the code in the repository. The endpoint audit command lists the AI tools, MCP servers, editor extensions and global npm packages on a developer machine and checks them for malware, which is a different threat surface from the repository you cloned. Agent mode finds Claude Code and other agents and then writes JSON and never prompts, so an agent cannot stall the scan with a question. And the inventory feature produces a CycloneDX 1.7 xBOM of the AI libraries and the crypto the code uses, alongside a CBOM. The policy documentation also references an Agent Skill in the .claude/skills directory that writes a policy for you, and the use case list mentions a GitHub Action that comments on a pull request adding a package, a workflow or a finding, and fails the check on an attack.

## The build system, and what the dependency list reveals

The repository is a Go workspace with a JavaScript workspace on top. The go.mod requires go 1.26.3 and pulls in a set of libraries that map directly onto the feature list: cel-go for the policy language, cyclonedx-go and go-spdx for the inventory formats, osv-scalibr and rustaudit for the vulnerability side, packageurl-go for the package URLs that key the suppressions, go-containerregistry and the moby client for image scanning, go-git for the repository target, and go-tree-sitter for parsing, which is how the tool reads source files well enough to find the crypto and AI library calls. There is a SafeDep gRPC API client generated from a buf.build schema, which is the transport to the hosted intelligence service, and posthog-go, which is the telemetry dependency worth noting given the README's claim that no account is needed. The Makefile is thorough, with a check target that builds, vets for Linux, macOS and Windows, runs the tests, lints only the changed lines against origin/v2 and runs a hermetic acceptance suite.

## Conclusion

vet suits a team that wants a supply chain check in pull request review and in CI, that wants the decision about what fails written as a policy file rather than left to a person, and that is willing to run a tool that reaches a hosted intelligence service. It is the wrong choice if you need the check to run with no network access at all, since the malicious package detection depends on SafeDep Threat Intel, and a poor fit if you want the scanner to be the only source of truth, because vet reports what it finds and the policy decides what to fail on, leaving judgement to you. Before adopting the v2 branch, read the v2.0.0 release notes, since they map each v1 command and flag to v2, and check whether the policy file you write is portable between the two lines.

## FAQ

### What does vet check?

It checks each package against SafeDep Threat Intel, known vulnerabilities with the fixed version to upgrade to, risky workflows such as dangerous triggers, template injection, exposed secrets and actions with no pinned commit SHA, lockfile tampering from untrusted registries and versions inside a cooldown window, and it inventories the AI libraries and crypto algorithms your code calls.

### What can vet scan?

A directory, which is the default, a git repository by URL, a container image as an OCI reference or an image tarball, an SBOM in CycloneDX or SPDX form, a single package by package URL, and the tools on the machine with vet endpoint audit. It reads lockfiles and manifests for npm, PyPI, Go, Maven, Gradle, Cargo, RubyGems, NuGet, Packagist, Pub and more.

### How do I write a vet policy?

In a vet-policy.yml file with a version, a list of rules and a list of suppressions. Rules have an id, a when expression written in CEL and an action, and suppressions are keyed by a package URL with a reason and an expires date after which the finding reappears. The README points at a policy.md page and an Agent Skill that writes a policy for you.

### Does vet install or run the dependencies it scans?

No. The documentation states that vet reads the lockfiles and manifests of the supported ecosystems along with the GitHub Actions workflows and the AI agent configs, and that it does not install or run any of them. Controls then turn that data into findings.

### Is vet v2 stable?

No, the v2 branch is in alpha, with dated alpha releases such as v2.0.0-alpha.20261014124335. The stable line is v1 on the main branch and stays the latest release, and the v2.0.0 release notes map each v1 command and flag to v2.

## Sources

- [License: Apache-2.0](https://github.com/safedep/vet/blob/v2/LICENSE)
- [Project website](https://safedep.io)
- [README](https://github.com/safedep/vet/blob/v2/README.md)
- [Releases](https://github.com/safedep/vet/releases)
- [safedep/vet on GitHub](https://github.com/safedep/vet)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/safedep-vet
