Skip to main content

Sub-second security gates that do not punish the team.

Adding a SAST step to CI is easy. Adding one that does not take 20 minutes per run, flag 500 false positives at the team's shared Slack channel, or require every contributor to sign up for a third-party account is harder.

Vulkro is designed for the gate. Single binary install, scan times measured per file in milliseconds, deterministic exit codes, and the right output formats for whichever CI you use.

The gate contract

vulkro scan --fail-on critical,high --format sarif --output vulkro.sarif

Three exit codes, every subcommand, by contract:

ExitMeaning
0Scan completed, no findings at or above the --fail-on threshold
1Scan completed, findings reported (or license-block)
2Error: bad arguments, IO failure, internal crash

This is in the --help text of every subcommand. Your CI's if exit_code in (0, 1) logic is the right shape; exit 2 is a "something broke, page someone" signal.

Baseline + ratchet for the retrofit

A repo that has been running without SAST for years will not turn green on day one. Two options:

Baseline once, ratchet forever. Commit the current state into .vulkro-baseline.json. Subsequent scans with --ratchet (auto-discovers the baseline file) only fail on findings the PR introduces. Existing debt is tracked separately and burned down on its own cadence.

Compare against a base ref. vulkro scan --gate-vs origin/main diffs against a ref and fails only on NEW findings the working branch introduces. Useful for PRs where the baseline approach would be too coarse.

Either way the security team gets the visibility they want without the team getting a "burn down 4,000 findings" assignment they will never finish.

Output formats per CI

CI / ToolRecommended formatFlag
GitHub Code ScanningSARIF--format sarif
GitHub PR inline commentsgh-pr--format gh-pr
GitLab Security DashboardSARIF--format sarif
Any dashboard with JUnitJUnit XML--format junit
Any dashboard with CSVCSV--format csv
Stream to a downstream toolNDJSON--format ndjson
Human-readable terminalDefault table(no flag needed)

SARIF is the workhorse: it works in GitHub Code Scanning, GitLab, Azure DevOps, BitBucket, and most other dashboards that have implemented the spec.

GitHub Actions in 12 lines

name: vulkro
on:
pull_request:
push:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # full history so --gate-vs works
- run: curl -fsSL https://install.vulkro.com | sh
- run: vulkro scan --ratchet --format sarif --output vulkro.sarif
- uses: github/codeql-action/upload-sarif@v3
if: always()
with: { sarif_file: vulkro.sarif }

if: always() ensures the SARIF uploads even when Vulkro returns exit 1 (findings present), so the Code Scanning tab gets the data and the build still fails the way you want it to.

GitLab CI in 8 lines

vulkro:
image: ubuntu:24.04
before_script:
- curl -fsSL https://install.vulkro.com | sh
script:
- vulkro scan --ratchet --format sarif --output vulkro.sarif
artifacts:
reports:
sast: vulkro.sarif

GitLab's sast report type ingests SARIF natively.

Pre-commit hook

# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: vulkro
name: vulkro scan
entry: vulkro scan --fail-on critical
language: system
pass_filenames: false
types_or: [python, javascript, typescript, go]

pass_filenames: false because vulkro takes a single project root (not a list of files) and cross-file taint flow matters, so scanning the project is the right primitive. types_or scopes the hook to only fire when files in the supported languages change. Vulkro's ci preset is fast enough that a full scan in a pre-commit hook is practical (sub-5s on most projects under 100k LoC).

Performance

ScenarioTypical scan time
Pre-commit (single file change)< 200ms
PR diff (10 files)< 1s
Full project (10k LoC)3-5s
Full project (100k LoC)20-40s
Full project (1M LoC)2-4min

Sub-second on the common cases is the target. The default tree- sitter parsing pipeline is fast enough for most codebases; deeper inter-procedural taint adds time but only on the rules that need it.

Honest comparison

vs. cloud SAST products (Snyk Code, Semgrep Cloud, Checkmarx): Vulkro does not require an account, does not upload code, and does not auto-renew. Performance is generally faster because there is no upload step. The trade-off: no shared dashboard or cross-team triage UI.

vs. CodeQL via GitHub Actions: CodeQL is excellent and free for public repos. Vulkro complements it (different rule set, faster scans, easier multi-language story); the two coexist in the same SARIF pipeline. For private repos GHAS pricing kicks in; Vulkro Pro at $19 is the alternative.

vs. Semgrep CE: Vulkro Free has substantially higher recall on the public benchmark (42 vs 12 of 55 bugs caught). Both are license-friendly for CI use.

Read the full benchmark methodology · CLI reference · Output formats