Skip to main content

Suppressing findings

A finding you have reviewed can be hidden three ways. Each keeps the reason in version control.

UseWhen
.vulkro/triage.tomlOne finding: false positive or accepted risk.
In-source commentA line or file, with the reason next to the code.
[[suppress]] in vulkro.tomlA rule or a path across the repository.

To see everything that is hidden, run with VULKRO_NO_SUPPRESS=1.

Triage file​

.vulkro/triage.toml holds decisions keyed by finding id. Every surface reads it (the CLI, the local console, the VS Code extension, the MCP server), so a finding marked once disappears everywhere. The console and the extension write it for you; vulkro explain <ID> prints an entry ready to paste.

schema = 1

[[finding]]
id = "js-taint-sql-001:3ad26e6c1266780c"
rule = "js-taint-sql-001"
file = "src/routes/users.js"
status = "false_positive" # open | confirmed | false_positive | accepted_risk | fixed
reason = "Table name comes from a fixed allowlist."
expires = "2026-12-31" # optional

false_positive and accepted_risk need a reason. Commit the file and make sure git does not ignore it.

In-source comments​

// vulkro:disable next-line <rule-id>[, <rule-id>, ...]
// vulkro:disable-line <rule-id>
// vulkro:disable-file <rule-id>
// vulkro:disable-file (every rule in the file)
/* vulkro:disable next-line <rule-id> */
<!-- vulkro:disable next-line <rule-id> -->
// vulkro:disable next-line cors-wildcard reason="public read-only API"
app.use(cors({ origin: "*" }));

Use # in Python. The rule id is the detector slug (for example cors-wildcard) or an OWASP code (API1); * means every rule. A directive inside a string literal is ignored. The scan prints how many findings comments suppressed.

Repo-wide suppressions in vulkro.toml​

[[suppress]]
rule = "literal-string-secret" # exact rule slug, or a full <rule>:<hash> id
path = "tests/**"
reason = "test fixtures"
expires = "2026-12-31" # optional review date

rule must match exactly. Get the slug from vulkro explain <ID> or the rule field in JSON. An entry with only path hides everything under that glob. After expires, the entry stops matching and the scan warns.

Team policy (org-wide enforcement)​

[team_policy]
require_suppression_reason = true
require_suppression_expiry = true
max_suppression_days = 90

[team_policy.quality_gate]
max_critical_findings = 0
fail_on_new_high = true

An entry that breaks the policy is not applied, and the scan says why. Gate floors merge with [quality_gate] (the stricter wins) and run on every scan, exiting 1 on a breach.

See also: Baselines, vulkro explain