Every VulnCheck CI integration is the same five steps; install a pinned CLI, expose VC_TOKEN, scan, gate, publish. So any platform that can run a shell script in a container can run it. VulnCheck in CI/CD explains each step; this page applies them to platforms without a guide of their own.
# 1. Install a pinned CLI
VC_CLI_VERSION=1.1.0
ARCH="$(uname -m)"
case "$ARCH" in x86_64) ARCH=amd64 ;; aarch64) ARCH=arm64 ;; esac
curl -sSL "https://github.com/vulncheck-oss/cli/releases/download/v${VC_CLI_VERSION}/vulncheck_${VC_CLI_VERSION}_linux_${ARCH}.tar.gz" | tar -xz -C /tmp
install -m 0755 "/tmp/vulncheck_${VC_CLI_VERSION}_linux_${ARCH}/bin/vulncheck" /usr/local/bin/vulncheck
# 2. VC_TOKEN comes from the platform's secret store — never from the repository
# 3. Scan
vulncheck scan . --json > scan.json
jq -r '"\((.vulnerabilities // []) | length) vulnerabilities found"' scan.json
# 4. Gate
jq -e --argjson max 7.0 '
[ (.vulnerabilities // [])[]
| select((.cvss_base_score // 0 | tonumber? // 0) >= $max or .in_kev) ] | length == 0
' scan.json > /dev/null || {
echo "VulnCheck policy breach:"
jq -r --argjson max 7.0 '
(.vulnerabilities // [])[]
| select((.cvss_base_score // 0 | tonumber? // 0) >= $max or .in_kev)
| " \(.cve) \(.name)@\(.version) CVSS \(.cvss_base_score) KEV \(.in_kev) fixed in \(.fixed_versions // "n/a")"
' scan.json
exit 1
}
# 5. Publish scan.json as a build artifact
Three things trip people up on every platform:
vulncheck scan exits 0 even when it finds critical vulnerabilities, so step 4 is what fails your build. Without it the job goes green with findings in the log.vulnerabilities key entirely, so (.vulnerabilities // [])[] is required — iterating it unguarded makes jq exit 5 on a repository with nothing wrong with it. .cvss_base_score // 0 | tonumber? // 0 guards the other end: a finding without a CVSS score would otherwise abort the whole program on tonumber, with the same exit 5, before .in_kev is evaluated.install.sh script is glibc-only and treats --sudo as available even in a root container, where it silently installs nothing. The tarball above works everywhere, Alpine included.Add VC_TOKEN under Repository settings > Repository variables with Secured ticked.
image: debian:bookworm-slim
definitions:
steps:
- step: &vulncheck-scan
name: Scan with VulnCheck
script:
- apt-get update -qq && apt-get install -y -qq --no-install-recommends ca-certificates curl jq
- export VC_CLI_VERSION=1.1.0
- curl -sSL "https://github.com/vulncheck-oss/cli/releases/download/v${VC_CLI_VERSION}/vulncheck_${VC_CLI_VERSION}_linux_amd64.tar.gz" | tar -xz -C /tmp
- install -m 0755 "/tmp/vulncheck_${VC_CLI_VERSION}_linux_amd64/bin/vulncheck" /usr/local/bin/vulncheck
- vulncheck scan . --json > scan.json
- jq -r '"\((.vulnerabilities // []) | length) vulnerabilities found"' scan.json
- |
jq -e --argjson max 7.0 '
[ (.vulnerabilities // [])[]
| select((.cvss_base_score // 0 | tonumber? // 0) >= $max or .in_kev) ] | length == 0
' scan.json > /dev/null || { echo "VulnCheck policy breach"; exit 1; }
artifacts:
- scan.json
pipelines:
pull-requests:
'**':
- step: *vulncheck-scan
branches:
main:
- step: *vulncheck-scan
Add VC_TOKEN as a project environment variable, or to a context shared across projects.
version: 2.1
jobs:
vulncheck-scan:
docker:
- image: cimg/base:current
environment:
VC_CLI_VERSION: 1.1.0
VC_CVSS_THRESHOLD: '7.0'
steps:
- checkout
- run:
name: Install the VulnCheck CLI
command: |
curl -sSL "https://github.com/vulncheck-oss/cli/releases/download/v${VC_CLI_VERSION}/vulncheck_${VC_CLI_VERSION}_linux_amd64.tar.gz" | tar -xz -C /tmp
sudo install -m 0755 "/tmp/vulncheck_${VC_CLI_VERSION}_linux_amd64/bin/vulncheck" /usr/local/bin/vulncheck
vulncheck version
- run:
name: Scan
command: |
vulncheck scan . --json > scan.json
jq -r '"\((.vulnerabilities // []) | length) vulnerabilities found"' scan.json
- run:
name: Gate on findings
command: |
jq -e --argjson max "$VC_CVSS_THRESHOLD" '
[ (.vulnerabilities // [])[]
| select((.cvss_base_score // 0 | tonumber? // 0) >= $max or .in_kev) ] | length == 0
' scan.json > /dev/null || { echo "VulnCheck policy breach"; exit 1; }
- store_artifacts:
path: scan.json
workflows:
security:
jobs:
- vulncheck-scan
Add vc_token as a repository secret. The example below is Drone; Woodpecker takes the same steps with the top-level kind, type and name keys removed.
kind: pipeline
type: docker
name: security
steps:
- name: vulncheck-scan
image: debian:bookworm-slim
environment:
VC_TOKEN:
from_secret: vc_token
VC_CLI_VERSION: 1.1.0
commands:
- apt-get update -qq && apt-get install -y -qq --no-install-recommends ca-certificates curl jq
- curl -sSL "https://github.com/vulncheck-oss/cli/releases/download/v${VC_CLI_VERSION}/vulncheck_${VC_CLI_VERSION}_linux_amd64.tar.gz" | tar -xz -C /tmp
- install -m 0755 "/tmp/vulncheck_${VC_CLI_VERSION}_linux_amd64/bin/vulncheck" /usr/local/bin/vulncheck
- vulncheck scan . --json > scan.json
- jq -r '"\((.vulnerabilities // []) | length) vulnerabilities found"' scan.json
- |
jq -e --argjson max 7.0 '
[ (.vulnerabilities // [])[]
| select((.cvss_base_score // 0 | tonumber? // 0) >= $max or .in_kev) ] | length == 0
' scan.json > /dev/null || { echo "VulnCheck policy breach"; exit 1; }
Expose VC_TOKEN through your agent's environment hook or secrets helper, then run the scan in a container:
steps:
- label: 'Scan with VulnCheck'
plugins:
- docker#v5.11.0:
image: debian:bookworm-slim
propagate-environment: true
environment:
- VC_TOKEN
commands:
- apt-get update -qq && apt-get install -y -qq --no-install-recommends ca-certificates curl jq
- export VC_CLI_VERSION=1.1.0
- curl -sSL "https://github.com/vulncheck-oss/cli/releases/download/v${VC_CLI_VERSION}/vulncheck_${VC_CLI_VERSION}_linux_amd64.tar.gz" | tar -xz -C /tmp
- install -m 0755 "/tmp/vulncheck_${VC_CLI_VERSION}_linux_amd64/bin/vulncheck" /usr/local/bin/vulncheck
- vulncheck scan . --json > scan.json
- |
jq -e --argjson max 7.0 '
[ (.vulnerabilities // [])[]
| select((.cvss_base_score // 0 | tonumber? // 0) >= $max or .in_kev) ] | length == 0
' scan.json > /dev/null || { echo "VulnCheck policy breach"; exit 1; }
artifact_paths:
- scan.json
Kubernetes-native runners such as Tekton, Argo Workflows and GitLab's Kubernetes executor need nothing special: run the generic recipe in a step container, mount VC_TOKEN from a Secret, and write scan.json to a shared workspace for a later step to publish.