kagami
kagami checks whether there are any publicly disclosed vulnerabilities in a list of defined software.
Package audits such as npm audit or Dependabot only see what is written in a lockfile. kagami is
for the software they cannot see: a PHP runtime installed on a server, Docker Engine on a host, or
a controller pinned by its image tag in a Kubernetes manifest. Write down what you run in a YAML
file, and kagami looks each version up in the GitHub Advisory Database
or in the security advisories that a project publishes in its own GitHub repository.
Installation
Install kagami from crates.io with Cargo (Rust 1.91 or later):
[!TIP] The crate is named
kagami-clibecause the namekagamiis taken on crates.io by an unrelated project. The installed command iskagami.
Usage
Write the software you run into kagami.yaml:
targets:
# Looked up in the GitHub Advisory Database by package name.
- name: k8s.io/ingress-nginx
version: 1.11.4
ecosystem: go
advisory_type: github
# Looked up in the advisories published in the php/php-src repository.
- version: 8.5.9
advisory_type: github_repository
repository_path: php/php-src
Then run kagami in the same directory:
$ kagami
25 Advisories found for 2 targets - Critical 3, High 7, Medium 12, Low 3, Unknown 0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📦 k8s.io/ingress-nginx@1.11.4 Github go
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
9 Advisories found - Critical 1, High 5, Medium 2, Low 1, Unknown 0
Critical - ingress-nginx admission controller RCE escalation
ID GHSA-mgvx-rpfc-9mpv / CVE-2025-1974
URL https://github.com/advisories/GHSA-mgvx-rpfc-9mpv
CVSS v3 9.8 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
CVSS v4 N/A
EPSS 99.384% (99.9th percentile)
Published 2025-03-25 (updated 2026-02-04)
Affected go/k8s.io/ingress-nginx < 1.11.5 (patched: 1.11.5)
go/k8s.io/ingress-nginx >= 1.12.0-beta.0, < 1.12.1 (patched: 1.12.1)
...
The kagami.yaml of this repository is a larger example.
kagami [OPTIONS] [CONFIG_FILE_PATH]
CONFIG_FILE_PATH: the config file to read (default:kagami.yaml)-o,--output-format:text(default),json,yamlorsimple-markdown-text-l,--log-level:error,warn(default),info,debugortrace
The options override the settings in the config file. Logs are written to stderr, so they do not mix with the output.
Configuration
Targets
| Field | Required | Description |
|---|---|---|
advisory_type |
Yes | Where to look for advisories: github or github_repository (see below). |
version |
Yes | The version you run, as a full semantic version like 1.29.0. 1.29 and v1.29.0 are rejected. |
name |
For github |
The package name in the GitHub Advisory Database, like k8s.io/kubernetes. With github_repository it is only the display name. |
ecosystem |
No | Limits the github search to one ecosystem, like go, npm or pip. |
repository_path |
For github_repository |
The repository that publishes the advisories, as owner/repo. |
github or github_repository
githubsearches the GitHub Advisory Database by package name. GitHub reviews these advisories and normalizes their version ranges, so prefer this type whenever the software is listed there. It does not have to be a library you depend on: Kubernetes (k8s.io/kubernetes), ingress-nginx (k8s.io/ingress-nginx), Docker Engine (github.com/moby/moby) and Argo CD (github.com/argoproj/argo-cd/v2) are listed as Go modules.github_repositorylists the advisories that a project publishes in the "Security" tab of its own GitHub repository. Use it for software that is not in the database, such as the PHP interpreter (php/php-src) or Envoy Gateway (envoyproxy/gateway). New advisories also show up here before GitHub has reviewed them into the database.
Other settings
| Field | Default | Values |
|---|---|---|
output_format |
text |
text, json, yaml, simple_markdown_text |
log_level |
warn |
error, warn, info, debug, trace |
Output
| Format | Description |
|---|---|
text |
A colored report for the terminal. |
json, yaml |
The full results as structured data, for scripts and other tools. |
simple-markdown-text |
One line per advisory with its severity and link, for posting to Slack or GitHub or Teams. |
kagami exits with 0 once the check has finished, whether or not it found advisories, and with
1 when the config file is invalid or a request to GitHub fails. To fail a CI job when advisories
are found, check the JSON output, for example with jq:
|
GitHub API token
kagami reads the advisories through the GitHub REST API. It takes a token from the first of these that is available:
- The
GH_TOKENorGITHUB_TOKENenvironment variable gh auth token, if you are logged in with the GitHub CLI
Without a token kagami calls the API anonymously, which GitHub limits to 60 requests per hour.
[!IMPORTANT] kagami only reads public data, so the token needs no extra scopes or permissions.
How version ranges are read
kagami matches the target version against the vulnerable version ranges of each advisory.
- Ranges in the GitHub Advisory Database are normalized by GitHub.
- Ranges in repository advisories are written by hand, in shapes like
>= v1.19.0,All,1.2.0 through 1.8.7or1.20.1 and earlier. kagami rewrites the shapes whose meaning is clear into semver ranges. A range that it still cannot read is logged as a warning and treated as not affecting the target, so check those advisories yourself. - A list of upper bounds such as
< 1.8.4, < 1.9.1is read as one fix per release branch (>= 1.8.0, < 1.8.4 || >= 1.9.0, < 1.9.1). - A pre-release target such as
1.32.0-rc.2is also checked as the release it leads to (1.32.0).
Hand-written ranges do not always describe every release branch precisely, so read the ranges in the output before acting on them.
Development
The Rust toolchain is pinned in rust-toolchain.toml, and
rustup toolchain install installs it. CI runs these checks on every pull request:
cargo test works as well if you do not have cargo-nextest.
Security
See SECURITY.md for how to report a vulnerability in kagami.
License
kagami is released under the MIT License.
Copyright (c) 2026 ZUNDA Inc.