A lightweight system agent that collects server information and installed packages, then reports them to a VulTrack vulnerability management server.
VulTrack Agent was developed with AI assisted coding. Be aware there might be dragons.
The VulTrack Server can be found in this repository.
- Static Binary: No external runtime dependencies, easy deployment
- Flexible Configuration: Config file, environment variables, or command-line flags
- Automatic Package Detection: Supports dpkg (Debian/Ubuntu)
- Robust Error Handling: Retry logic with exponential backoff
- Automatic Token Refresh: Short-lived access tokens are refreshed automatically; the agent re-enrolls itself when the refresh token expires
- Systemd Integration: Pre-configured service for easy installation
- Ansible Role: Included Ansible role for automated fleet deployment
An Ansible role is included at ansible/roles/vultrack_agent/ for automated
installation, configuration, enrollment, and service management across a fleet
of servers.
For manual installation options, see INSTALL.md.
- Ansible 2.12+
- Target hosts: Ubuntu with
systemd
# Version to install
vultrack_agent_version: "1.0.0"
# Installation method: "deb" (recommended) or "binary"
vultrack_agent_install_method: "deb"
# VulTrack server URL — REQUIRED
vultrack_agent_server_url: ""
# Set to true to enroll the agent during the play
# When true, vultrack_agent_enrollment_key must also be set
vultrack_agent_enroll: false
# IMPORTANT: enrollment_key must remain in the config permanently.
# The agent needs it to re-enroll automatically when the refresh token
# expires or is revoked.
vultrack_agent_enrollment_key: ""
# Agent configuration
vultrack_agent_refresh_token_file: "/var/lib/vultrack-agent/refresh.token"
vultrack_agent_report_interval: "1h"
vultrack_agent_log_level: "info"
vultrack_agent_log_file: ""
vultrack_agent_insecure: false
vultrack_agent_ca_cert: ""
# Systemd service management
vultrack_agent_service_state: "started"
vultrack_agent_service_enabled: true
# GitHub source (usually no need to change)
vultrack_agent_github_url: "https://github.com"
vultrack_agent_github_repo: "RiskIdent/VulTrack-Agent"
# Installation paths (usually no need to change)
vultrack_agent_bin_path: "/usr/local/bin/vultrack-agent"
vultrack_agent_config_dir: "/etc/vultrack-agent"
vultrack_agent_config_file: "/etc/vultrack-agent/config.yaml"- name: Deploy VulTrack Agent
hosts: all
become: true
roles:
- role: vultrack_agent
vars:
vultrack_agent_version: "1.0.0"
vultrack_agent_server_url: "https://vultrack.example.com"
vultrack_agent_enroll: true
vultrack_agent_enrollment_key: "{{ lookup('env', 'VULTRACK_ENROLLMENT_KEY') }}"- name: Deploy VulTrack Agent
hosts: all
become: true
roles:
- role: vultrack_agent
vars:
vultrack_agent_version: "1.0.0"
vultrack_agent_server_url: "https://vultrack.example.com"- name: Deploy VulTrack Agent (binary)
hosts: all
become: true
roles:
- role: vultrack_agent
vars:
vultrack_agent_version: "1.0.0"
vultrack_agent_install_method: "binary"
vultrack_agent_server_url: "https://vultrack.example.com"- Maps the system architecture (
aarch64→arm64, others →amd64) - Validates required variables (
vultrack_agent_server_url, andvultrack_agent_enrollment_keywhen enrolling) - Creates the system user and config directory (
/etc/vultrack-agent/) - Downloads and installs the agent from GitHub Releases (
.debor binary) - Writes the configuration file from template
- Optionally runs
vultrack-agent enroll(skipped if refresh token file already exists — idempotent) - Ensures the systemd service is enabled and running
Configuration is loaded from three sources in the following priority order (highest to lowest):
- Command-line flags
- Environment variables
- Config file
Default location: /etc/vultrack-agent/config.yaml
A custom path can be specified with the global --config flag:
vultrack-agent --config /path/to/config.yaml reportFull reference:
# VulTrack server URL (required)
server_url: https://vultrack.example.com
# Enrollment key (required — keep this permanently in the config).
# Used for initial enrollment and for automatic re-enrollment when the
# refresh token expires or is revoked.
enrollment_key: ""
# Path to persist the refresh token on disk.
# The access token is held in memory only and is never written to disk.
refresh_token_file: /var/lib/vultrack-agent/refresh.token
# How often to send reports in daemon mode (default: 1h)
# Examples: 30m, 1h, 2h, 24h
report_interval: 1h
# Log level: debug, info, warn, error (default: info)
log_level: info
# Path to log file (empty = stdout/journald)
log_file: ""
# Skip TLS certificate verification — only use for testing!
insecure: false
# Path to a custom CA certificate in PEM format (optional)
ca_cert: ""An annotated example is available at contrib/config.yaml.example.
| Variable | Description |
|---|---|
VULTRACK_SERVER_URL |
VulTrack server URL |
VULTRACK_ENROLLMENT_KEY |
Enrollment key (keep permanently) |
VULTRACK_REFRESH_TOKEN_FILE |
Path to refresh token file |
VULTRACK_REPORT_INTERVAL |
Report interval (e.g. 1h, 30m) |
VULTRACK_LOG_LEVEL |
Log level (debug, info, warn, error) |
VULTRACK_LOG_FILE |
Path to log file |
VULTRACK_INSECURE |
Skip TLS verification (true/false) |
VULTRACK_CA_CERT |
Path to custom CA certificate |
| Flag | Description |
|---|---|
--config |
Path to config file |
--server-url |
VulTrack server URL |
--enrollment-key |
Enrollment key |
--refresh-token-file |
Path to refresh token file |
--log-level |
Log level |
--log-file |
Path to log file |
--insecure |
Skip TLS verification |
--ca-cert |
Path to custom CA certificate |
Register the agent with the VulTrack server. Requires an enrollment key obtained from the VulTrack web UI.
sudo vultrack-agent enroll --enrollment-key YOUR_ENROLLMENT_KEYOn success, the refresh token is saved to refresh_token_file. The access
token is held in memory only.
To force re-enrollment (revokes the existing registration):
sudo vultrack-agent enroll --enrollment-key YOUR_ENROLLMENT_KEY --forcesudo vultrack-agent report# Recommended: run as a systemd service
sudo systemctl start vultrack-agent
# Or run manually in the foreground
sudo vultrack-agent daemonThe daemon handles SIGINT and SIGTERM for graceful shutdown and sends an
initial report immediately on startup. It automatically refreshes the access
token and re-enrolls using enrollment_key when the refresh token expires.
Collect all data locally and write it as formatted JSON — without contacting the server. Useful for debugging or offline inspection:
sudo vultrack-agent export -o report.json
sudo vultrack-agent export | jq .Display the active configuration, token state, and validate the token against the server:
sudo vultrack-agent status| Field | Description | Example |
|---|---|---|
hostname |
FQDN of the system | server01.example.com |
osFamily |
OS family | ubuntu, debian, rhel, centos, rocky, alma |
osRelease |
OS version | 24.04, 12, 9.4 |
osCodename |
OS codename (if available) | noble, bookworm |
kernel |
Kernel version (uname -r) |
6.8.0-31-generic |
arch |
System architecture | amd64, arm64 |
ipv4Addrs |
Non-loopback IPv4 addresses | ["192.168.1.10"] |
packageManager |
Detected package manager | dpkg, rpm |
For each installed package:
| Field | Description |
|---|---|
name |
Package name |
version |
Full version string |
arch |
Package architecture |
source |
Source package name |
Packages are collected via dpkg-query on Debian/Ubuntu systems and
rpm -qa on RHEL/CentOS/Rocky/Alma systems.
The agent uses two tokens:
| Token | Storage | Lifetime |
|---|---|---|
| Access token (JWT) | Memory only, never written to disk | Short-lived (default 24 h) |
Refresh token (rt_…) |
refresh_token_file (0600) |
Long-lived (default 90 days) |
The agent manages token renewal automatically:
- If a valid access token is in memory — use it directly.
- If the access token is absent or expired — exchange the refresh token for a new pair.
- If the refresh token is rejected (401) — re-enroll automatically using
enrollment_key. - After enrollment, if the agent status is
pending— wait for admin approval before reporting.
This is why enrollment_key must remain permanently in the config — it enables
fully autonomous recovery without manual intervention.
| Condition | Behavior |
|---|---|
| Network error | Retry up to 3 times with exponential backoff (1s, 2s, 4s) |
401 on report |
Refresh access token and retry once |
401 on token refresh |
Re-enroll with force=true using enrollment_key |
401 on enrollment |
Enrollment key invalid — log error and exit |
403 Forbidden |
Agent pending approval or revoked — no retry |
409 Conflict on enroll |
Hostname already registered — use --force to re-enroll |
- Refresh token file is stored with
0600permissions (owner read-only) - Refresh token directory is created with
0700permissions - Access token is held in memory only and never written to disk
- Token writes use an atomic write-then-rename pattern to prevent corruption
- TLS certificate validation is enforced by default
- Custom CA certificates can be provided for internal PKI environments
- Tokens and enrollment keys are never fully written to logs (only first 8 characters)
- Ansible tasks use
no_log: truefor steps that handle secrets
The systemd unit included in the package and in contrib/vultrack-agent.service
provides:
- Automatic restart on failure
- Network dependency (
network-online.target) - Security hardening (
NoNewPrivileges,PrivateTmp, etc.) - Logging to the systemd journal
sudo journalctl -u vultrack-agent -f
sudo journalctl -u vultrack-agent -n 100
sudo journalctl -u vultrack-agent --since todayvultrack-agent/
├── cmd/
│ └── vultrack-agent/
│ └── main.go # CLI entry point (6 commands)
├── internal/
│ ├── api/
│ │ └── client.go # HTTP client for VulTrack API v2
│ ├── collector/
│ │ ├── system.go # System information collection
│ │ └── packages.go # Package enumeration (dpkg/rpm)
│ └── config/
│ └── config.go # Configuration loading and validation
├── ansible/
│ └── roles/
│ └── vultrack_agent/ # Ansible role
├── contrib/
│ ├── vultrack-agent.service # Systemd unit file
│ └── config.yaml.example # Annotated example configuration
├── .github/
│ ├── dependabot.yml # Automated dependency updates
│ └── workflows/
│ ├── release.yml # Automated release workflow
│ └── zizmor.yml # GitHub Actions security scanning
├── build.sh # Multi-arch build script
├── INSTALL.md # Manual installation options
└── README.md
github.com/spf13/cobra— CLI frameworkgo.yaml.in/yaml/v4— YAML parsing- Standard library for everything else
- Go 1.21 or higher
dpkg-debfor creating Debian packages (apt install dpkg-dev)
MIT License