Skip to content

sbom_generate and vulnerability_scan

Software-composition analysis. sbom_generate catalogs what a target is built from, using Syft. vulnerability_scan matches packages against known vulnerabilities, using Grype.

Syft and Grype are separate installs

Both must already be on PATH. Kerkov never downloads, installs, or updates them — it invokes what you have, as a fixed argument vector with no shell.

They are two tools rather than one so an SBOM can be kept, inspected, and reused. Generate it once, then scan it as many times as the vulnerability database changes. Grype can also catalog a directory or image directly when a reusable SBOM is not worth having.

Target selection

Both tools take a target plus a source_type that says how to read it.

source_type sbom_generate vulnerability_scan
directory ✓ ✓
file ✓ ✗ — scan the containing directory instead
image ✓ ✓
sbom ✗ — Syft produces SBOMs ✓

Local targets must stay inside the engagement workspace. This is stricter than read and write, which honour absolute paths: a scan walks an entire tree, so the blast radius of a mistyped target is much larger. Copy or clone what you want scanned into the workspace first.

Container images are the exception — they are not workspace paths. image_source selects where the image comes from: auto, docker (a local daemon), or registry (bypassing any local runtime). For images, scope chooses between the squashed filesystem and all-layers.

sbom_generate

Parameters

Parameter Type Default Description
target string . Workspace-local directory or file, or an image reference.
source_type directory | file | image directory How to read the target.
image_source auto | docker | registry auto Images only.
output_format syft-json | cyclonedx-json | spdx-json syft-json Artifact format.
scope squashed | all-layers squashed Images only.
exclude array[string] — Syft path-exclusion globs.
timeout_seconds integer 300 Maximum Syft runtime.
max_packages integer 50 Packages returned to the model. The complete SBOM stays in the artifact.

Returns

A bounded package summary as JSON output. The complete SBOM document is written to artifacts/sbom/ in the engagement workspace, under a generated collision-proof name, and its exact path comes back in metadata.report_artifact. The scanner's console log lands beside it as metadata.log_artifact.

The JSON output carries status, engine, engine_version, runtime, format, source, source_type, package_count, returned_package_count, packages_truncated, counts_by_type, the packages themselves, and artifacts with the report and log paths.

For a completed scan, metadata carries status, engine, format, package_count, packages_truncated, report_artifact, log_artifact, and runtime_source.

A scan that finishes but whose report cannot be summarized returns status: "completed_unsummarized" with the artifact paths — the SBOM exists and is readable even when Kerkov could not normalize it.

Examples

{ "target": "src/", "source_type": "directory" }

A reusable CycloneDX SBOM of an image:

{
  "target": "nginx:1.25",
  "source_type": "image",
  "image_source": "registry",
  "output_format": "cyclonedx-json"
}

vulnerability_scan

Parameters

Parameter Type Default Description
target string . Workspace-local directory or SBOM file, or an image reference.
source_type directory | image | sbom directory How to read the target.
image_source auto | docker | registry auto Images only.
scope squashed | all-layers squashed Images only.
minimum_severity unknown | negligible | low | medium | high | critical unknown Minimum severity in the summary. The full report always keeps every match.
only_fixed boolean false Report only vulnerabilities with a known fix.
exclude array[string] — Grype path-exclusion globs, for cataloged sources.
update_database boolean true Let Grype check for and download its vulnerability database.
timeout_seconds integer 600 Maximum Grype runtime, database update included.
max_findings integer 50 Findings returned to the model.

update_database defaults to true because a stale database is a scan that misses things silently. Set it to false only for a deliberately offline scan against a cached database — and expect the results to be as old as the cache.

Returns

A severity-sorted summary as JSON output. The complete Grype JSON report goes to artifacts/vulnerability-scans/ in the engagement workspace, with its path and the scanner log's path in metadata.report_artifact and metadata.log_artifact.

The JSON output carries status, engine, engine_version, runtime, source, source_type, database (including when it was built), match_count, filtered_match_count, returned_finding_count, findings_truncated, minimum_severity, counts_by_severity, the findings, and artifacts.

For a completed scan, metadata carries status, engine, match_count, filtered_match_count, findings_truncated, report_artifact, log_artifact, runtime_source, and database_built.

Matches are a successful scan

success: false means the scan did not run — Grype was missing, the target was unreadable, the run timed out. Forty critical findings is success: true. Do not read a failure as "clean" or a success as "safe".

A failure carries reason and diagnostic_tail — the end of the scanner log — so the cause is visible without reading the artifact.

Examples

Scan the SBOM generated above, using the path sbom_generate returned in metadata.report_artifact:

{ "target": "artifacts/sbom/sbom-toolu_01abc-8f3k2p.cyclonedx.json", "source_type": "sbom" }

Actionable findings only:

{
  "target": ".",
  "source_type": "directory",
  "minimum_severity": "high",
  "only_fixed": true
}

An image straight from a registry:

{ "target": "target.example/api:latest", "source_type": "image", "image_source": "registry" }

Approval

Both prompt in strict and normal and run automatically in permissive and yolo. Neither has an allow rule, and the comment in approvals.yaml says why: a run may pull an image from a registry, refresh Grype's vulnerability database, write report artifacts, and consume substantial CPU, disk, and network.

Approval offers no broad rung for either tool — a saved approval covers that call and no other, since the cost of a run depends entirely on its target. timeout_seconds never reaches a saved rule.

Both are gated by EXECUTION_ENABLED; with execution off, calls return metadata.policy = "execution_disabled".

  • cve_lookup — a scan says which CVEs apply; cve_lookup says which of them matter. KEV listing and EPSS beat a raw CVSS ranking.
  • sast_scan — vulnerabilities in the code you wrote, rather than in the dependencies you pulled.
  • read — open the complete report at metadata.report_artifact; filter large reports with exec to inspect findings omitted from the summary.
  • recall — retrieve a previous scan's returned summary. The report file is not automatically indexed in the knowledge base.
  • exec — for Syft and Grype options these tools do not expose. You lose the artifact handling and the bounded output.