vmsctl
KISA 2026 · Ubuntu · Debian · Rocky · Alma · Amazon Linux

Check your Linux servers like you lint your code

One static binary reads a host's security configuration and gives one result per control, with the value, the file and the line behind every verdict. It only reads: it never changes the host.

Try it right now: scan this machine's root, read-only, without installing anything
$ docker run --rm -v /:/host:ro ghcr.io/with-developer/vmsctl:0.40.0 scan --root /host
vmsctl server · Overview
The dashboard's overview: a pass rate of 54 percent, results by status, the pass rate over 30 days, and counts of hosts

You can trust a result you can check

Most scanners give a verdict and leave you to find out why. vmsctl is built the other way round.

Evidence for every verdict

The value, the file and the line it came from, and whether it was set explicitly or is a default. There is no FAIL without a reason.

No guessed PASS

When a control cannot be decided (an unreadable file, a cut-off scan) the result is ERROR or MANUAL. Configuration is read the way the program reads it: PAM like libpam, login.defs like shadow-utils, shell files like bash.

Observation only

Rules are data, not scripts, so they cannot run commands. Password hashes, keys and tokens never appear in a result.

Run it on a host, get a clear list

Run it as root. The first profile is the KISA technical vulnerability assessment guide for critical infrastructure (Unix, U-01 to U-67, 2026 edition); other baselines are added as profiles over the same checks.

  • Hosts and images. A running system, a filesystem mounted elsewhere, or a container image straight from a docker save archive.
  • Many outputs. Table, JSON (with a schema), SARIF, JUnit, and one self-contained HTML report for many hosts.
  • Waivers with a reason. Accept a finding in vmsctl.yaml with an expiry date, and the result keeps its evidence.
$ sudo vmsctl scan
vmsctl v0.40.0 · kisa-2026 · web-01 (Ubuntu 24.04)

✗ FAIL   U-02   Password policy [high]
    ✗ accounts.password-min-length
        pam.password_quality.settings.minlen: not set
✗ FAIL   U-12   Session timeout [low]
    ✗ accounts.session-timeout-set
        not set; expected a value matching [1-9][0-9]*
✗ FAIL   U-18   Ownership and permissions of /etc/shadow [high]
    ✗ files.shadow-perms
        /etc/shadow: root:shadow 0640 — mode 0640 exceeds 0400
? MANUAL U-23   Set-ID programs are reviewed [high]
    ? files.review-setid
        /usr/bin/chage 2755 root
        … and 10 more

kisa-2026: 67 controls — 7 FAIL, 10 MANUAL, 29 PASS, 21 N/A

One dashboard for every server

Hosts scan themselves and push the result to vmsctl server. It keeps the history and shows the pass rate over time, what failed most, what got worse since the last scan, and the evidence behind each result with how to fix it.

The host list with search, filters, labels and a trend line for each host

Search, filter by label, sort. Each host shows its latest result and a trend line.

The server never connects to a host

Hosts push their results. To scan one on demand, its vmsctl agent dials out and waits for a “Scan now” from the dashboard, and it can only be asked for a profile the host allows.

Signed results

A host can sign what it sends, so a result stays evidence of what that host said even if the server is compromised later. The server keeps a hash-chained audit log.

Try it with no host

Open the live demo in your browser, or run vmsctl server demo: it starts a server with a made-up fleet of twelve hosts and prints a token to sign in with. Korean and English, light and dark. Every check explains itself in Korean too: what it looks at, why, and how to fix it.

Gate the image before it ships

vmsctl scan --image-tar reads a docker save or OCI archive with no daemon and no registry, and gives the same result as a scan inside a container made from that image. The repository is also a GitHub Action: it installs a verified release, uploads SARIF to code scanning and fails the build at the severity you choose.

Scanning images · Using vmsctl in CI

# any CI
docker save app:1.4 -o app.tar
vmsctl scan --image-tar app.tar --fail-on high

# GitHub Actions
- uses: with-developer/vmsctl@v0.40.0
  with:
    image: app:ci
    fail-on: high
    sarif-file: vmsctl.sarif

Supported systems

Every distribution below is scanned in Docker, stock and hardened, in the project's own tests.

Ubuntu 22.04 · 24.04 · 26.04 Debian 12 · 13 Rocky Linux · AlmaLinux 9 · 10 Amazon Linux 2023 CentOS / RHEL 7 (best effort)

Get started in three steps

Releases are signed with Sigstore and carry build provenance and an SBOM.

Install

Download the installer, read it, then run it. It verifies the archive's SHA-256 (and the signature, when cosign is installed).

curl -fsSLO https://raw.githubusercontent.com/with-developer/vmsctl/v0.40.0/install.sh
sudo sh install.sh -v v0.40.0

Or use a .deb or .rpm from the releases, the container image, or go install github.com/with-developer/vmsctl/cmd/vmsctl@v0.40.0.

Scan

One host, one report. For many hosts, save the JSON and build a single HTML report.

sudo vmsctl scan
sudo vmsctl scan --format json --output web-01.json
vmsctl report *.json --output report.html

See the whole fleet

Start with the demo. Then run your own server and push results from each host.

vmsctl server demo
# later: sudo VMSCTL_TOKEN=hlt_ing_... vmsctl scan --push https://vmsctl.example.org:8443