Findings

How findings are structured, ingested, and staged in Bevor

A finding is a single security observation — tied to a specific location in your code, carrying a severity and an explanation, and always living inside an analysis version. This page covers what a finding actually contains, the ways to get findings into Bevor, and the staging lifecycle every finding goes through before it becomes part of your security posture.

Anatomy of a Finding

Every finding has two required parts — a node (the entrypoint it impacts) — and 3 optional parts — metadata (what it is), a source (who produced it), and a location (where it occurs, in the context of the entrypoint).

Location

Bevor's security model is entrypoint-centric: findings are ultimately understood in terms of the entrypoints that reach them. A location can be expressed three ways:

  • By node id — the most direct method, for callers that already know Bevor's graph. Two ids are involved:

    • node_id — the entrypoint being analyzed.
    • location_id — where the finding actually occurs (optionally), if different from the entrypoint (e.g. "entrypoint A calls into vulnerable function B" — A is the node_id, B is the location_id).

    location_id defaults to node_id when omitted. Providing location_id alone — without a node_id — fans the finding out to every entrypoint that reaches that node. This is intentionally permissive: you can report a vulnerability in a shared internal function once, and Bevor will surface it against every entrypoint it affects.

  • By physical location — a file URI plus a region (line range, character offset/length, or byte offset/length). For tools that only know source coordinates and haven't resolved them to a Bevor node. Bevor resolves the region to node(s) internally.

  • By logical name — a fully-qualified symbol name (e.g. Owner.onlyOwner). For tools that only have a symbol reference.

Metadata

When present, metadata describes the finding itself: type, level (severity), name, explanation, and optionally recommendation and reference.

Note

Metadata is all-or-nothing. Submitting a finding without metadata is not an error — it explicitly marks that location as analyzed with no issues found, distinguishing "not yet looked at" from "looked at, clean." This matters for coverage: without it, there's no way to tell whether an entrypoint was skipped or was checked and passed.

In Bevor, type is well-defined, but we allow for you to pass any arbitrary type for your own purposes.

Source

An optional free-text field identifying which tool or pipeline produced the finding — bevor internal, bevor chat, slither, the name of your own scanner or agent, etc. Left empty for ad hoc or manually-entered findings. We highly recommend populating this field so you can assess performance and utility across different tool sets.

Getting Findings Into Bevor

As covered in Analyses, findings reach Bevor three ways: Bevor's own security pipeline, your own pipeline via BYOS, or Bevor's chat interface. This section is about the BYOS path — bringing findings from anywhere else.

Bevor's finding schema is the same whether it's typed by a human, generated by a script, or produced by an LLM agent — there's one shape to target, not a different format per integration:

  • Add one finding at a time — for manual triage or a single ad hoc observation. Via the Bevor CLI, .yaml/.yml files are supported. See the SDK or the CLI for more information.
  • Bulk import — for a batch from a tool or pipeline run. For the CLI, SARIF .sarif files, a .yaml/.yml file (including multiple findings in one file, ----separated), or a directory of YAML files are supported. See the SDK or the CLI for more information.

Tip

Any tool — including an LLM-driven agent — can target the native JSON/YAML schema directly rather than going through SARIF. Publishing the schema and a worked example means an integration only needs to produce well-shaped output once, with no translation layer in between.

An example finding, using the node-id location strategy:

source: my-local-ai-tool
metadata:
  type: reentrancy
  level: high
  name: Reentrancy in withdraw()
  explanation: >
    External call to msg.sender happens before the balance is updated,
    allowing a malicious contract to re-enter withdraw() and drain funds.
  recommendation: Apply checks-effects-interactions — update balances before the external call.
location:
  strategy: node_id
  node_id: node_a1b2c3
  location_id: node_d4e5f6

Staging and Committing

However a finding arrives, it doesn't immediately become part of the analysis version's persisted finding set. Findings are staged by default — think git add. A staged finding exists as a pending change against the current analysis version.

Each staged change carries a draft operation describing what will happen on commit — whether a new finding will be added, an existing finding's metadata will be edited, or a finding will be removed. This is what lets you review a batch of incoming findings (from a CI run, an agent, a bulk import) as a set of proposed changes before they take effect, the same way you'd review a diff before merging it.

  • Committing staged changes produces a new, immutable analysis version — see Creating New Versions.
  • Reverting a specific staged change discards it before commit, without affecting any other pending changes. Useful when a bulk import or an agent run produces something you don't want to keep, or you want to further triage with Bevor chat to de-dup, triage, or attest to these staged changes.
  • Editing a finding's metadata works the same way — it stages a metadata change rather than mutating the finding in place, and goes through the same commit/revert lifecycle as an addition.

Warning

Staged findings are not yet real. If you're building an integration that reads findings back to check ingestion succeeded, remember that a newly-added finding won't appear in the committed set — and won't affect security posture — until it's committed.

Acknowledgement vs. Staging

Acknowledgement is a separate, orthogonal concept from staging. Staging is about whether a change has been committed to the analysis version's history; acknowledgement is a review/triage status on a finding that's already committed — has a human looked at it and accepted, dismissed, or actioned it. Findings can be filtered by acknowledgement status independently of their staged/committed state, and acknowledging a finding has no effect on whether it's part of any particular analysis version.

On this page