Skip to main content
View Markdown ↗

Copy this page

Select and copy the Markdown below, then paste it into your LLM.

On this page

Check an artifact for vulnerabilities

The platform answers one question per artifact: which known advisories apply to the build that produced it. It finds that build in your workspace's own evidence and checks the dependencies the build actually used. The same check powers Pushgate's experimental vulnerability detection, which answers it for each push.

The check is experimental and advisory. Its results are never read by a policy decision or a gate, and nothing in them is a VEX statement.

What the platform needs from your build

An artifact can be checked only when the build that produced it was traced. That build must:

  • run under cilock run --trace on Linux;
  • record the commit with the git attestor, so the platform can tie the build to its commit;
  • upload its attestation collection to the platform, including any detached trace parts the run wrote.

A build without a trace is never answered with an empty list. It is reported as not checked, with the reason.

Ask with jctl

jctl get vulns with one selector returns the verdicts for a single artifact:

# A container image, by digest
jctl get vulns --image ghcr.io/acme/api@sha256:<64 hex>

# Any subject digest the build produced
jctl get vulns --subject sha256:<64 hex>

# The newest traced build of a commit
jctl get vulns --commit <40 hex>

# One traced attestation collection, by its gitoid
jctl get vulns --attestation <gitoid>

Pass exactly one of the four. The platform resolves the selector to the traced build it came from. The header names what it resolved to (the commit, the build and its collection) and which advisory snapshot answered. When several builds of one commit could answer, it uses the newest traced one and prints a WARNING line: pin the one you mean with --attestation. A related commit it found but did not follow is listed on a RELATED line.

FlagDefaultMeaning
--severityallOnly these severities: critical, high, medium, low, unknown.
--alloffInclude informational rows: advisories whose affected range the version is outside.
--wait60sHow long to wait for a check that is still running.
--tenantfrom JCTL_TENANT_ID, then the jctl context, then the tokenWhich workspace to read. A broken --context is refused rather than falling back to another workspace.
-o jsontableThe versioned jctl.vulns.v1 document.

Without a selector, jctl get vulns keeps its older behavior and lists findings from scanner attestations (--collection, --summary, --limit). Those flags are refused alongside a selector.

Reading the result

Each row carries a status:

StatusMeaning
affectedThe build's version of the package is affected by the advisory.
under_investigationPossibly affected: the version matches, and the evidence cannot show whether the vulnerable code ran.
unknownThe check could not decide. Never read as not affected.
not_affectedThe evidence shows the build is not affected.
informationalThe version is outside the advisory's affected range. Shown only with --all.

The MATCHER column names the check's own label and how the package was identified. The VEX, BY and AT columns are reserved for your own VEX statements and print - today: the header says when owner VEX is not available on your deployment.

Exit codes

CodeMeaning
0Checked. The table (or JSON) is the answer, even when it has no affected rows.
3NOT CHECKED with a code and a reason, for example no traced build for the artifact. Not a clean result.
4The command was used wrongly: two selectors, an empty value, an image without a digest, an unknown severity.
5The platform could not be asked. Check jctl auth whoami and the workspace.

A check still running past --wait prints PENDING with its check id. Run the same command again.

Where a dependency was

Pushgate's push card places each dependency in one of three stages: In the binary (compiled into what the build produced), Toolchain (the build ran it, and it is not in the output), and Not placed (the check could not tell which). The Pushgate page explains each one. The jctl verdict view does not print the stage today.

The product Vulnerabilities tab

A product's Vulnerabilities tab lists one row per vulnerability and component across the product's current builds, with the status Affected, Possibly affected or Not affected. Needs decision shows what nobody has answered yet; Resolved shows the rest. A row explains its status under Why this status: a statement you made, one your agent or pipeline made, or what the build read. When a statement and the build evidence disagree, the row is marked Contested. When a build read a file the fix changed after the statement was made, it says Evidence disagrees. The statement still decides; review it.

Below the list, Recent builds shows affected, possibly affected and not affected counts per build. Which of your builds read it looks up one advisory across every traced build in your workspace.

The tab fills from per-build results recorded against the product. A product with none says "No build of this product has vulnerability results yet. That is not the same as no vulnerabilities." To check a deployed artifact today, use jctl get vulns --image.

Why the answer is never a guess

A wrong "clean" tells you to stop looking, so the check says what it could not establish:

  • No traced build is "not checked", never zero findings.
  • A version match without evidence that the vulnerable code ran is possibly affected, not affected and not clean.
  • A trace that stopped early means a read may be missing, so the result cannot be not affected.
  • A severity the advisory does not score is "unscored", never low.
  • An advisory missing from the CISA KEV catalog is "KEV not known", never "not exploited".

Limits

  • The check names only the dependencies it can identify. The absence of a finding is not proof that a build is free of vulnerable code.
  • New advisories reach checks in about 11 minutes after OSV publishes them. Each answer names the advisory snapshot it was checked against, so an older answer can differ from a new check of the same build.
  • Under a merge queue, the commit you deploy is often not the commit you pushed. Check the deployed artifact (--image or --subject), not the push.
  • SBOM download for a checked build is planned and not yet generally available.