SARIF and CSV exports

The SARIF 2.1.0 and CSV exports: structure, fields, columns and ordering.

A report downloads in three formats: pdf, sarif and csv. This page describes the two machine-readable ones. The PDF report describes the third.

Downloading

All three come from one endpoint:

GET /api/engagements/{engagement_id}/reports/{report_id}/download?format=sarif

format accepts pdf, sarif or csv and defaults to pdf; any other value is rejected. The request needs a report record for the engagement, so a report must have been generated first. The report id gates access and selects nothing else: any of the engagement's report ids returns the same content.

Format Media type File name
sarif application/sarif+json pentr-report-{engagement_id}.sarif
csv text/csv pentr-report-{engagement_id}.csv

The console's SARIF and CSV buttons in the Report panel call the same endpoint.

Built at download

The PDF is a file written once, when the report is generated. The SARIF and CSV exports are rebuilt on every download: the server reads the findings and the seal record from the database, loads the framework's YAML file, maps the findings, and writes the export from the result.

If the framework file changes between the PDF's generation and a later download, the PDF and the export can carry different control ids for the same run. Two downloads of the same export made before and after such a change can differ in the same way.

Ordering

Both exports sort findings by severity, from critical to info, then by title, then by finding id. The order does not depend on the database. The PDF lists findings in stored order instead, so row n of the CSV and finding n of the PDF are generally different findings. Join on the finding id.

Unsealed runs

On an unsealed run, or a sealed run whose manifest could not be read, the per-finding artifact hashes are empty. They are not recomputed from the artifact store. SARIF states the seal state at run level, in properties.evidence_integrity. The CSV has no column for it: an empty artifact_sha256 cell looks the same whether the run is unsealed or the finding has no linked artifacts.

CSV

One header row, then one row per finding. The columns, in order:

Column Content
finding_id The finding's UUID.
severity critical, high, medium, low or info.
title The finding's title.
target The finding's affected asset.
cve CVE ids.
cvss The CVSS score, empty if none. The vector is not exported.
cwe CWE ids derived from keyword categories. See Severity and taxonomy.
attack_technique_ids ATT&CK technique ids.
wstg_ids OWASP WSTG ids.
control_ids The framework control ids the mapper assigned at download time.
phase The phase the finding was added in.
status unverified, verified, false_positive or not_exploitable.
artifact_sha256 SHA-256 hashes of the sealed artifacts linked to the finding.

Multi-value cells join their values with ; and are empty when there are none. The file is UTF-8 without a byte-order mark, and lines end in CRLF. Fields are quoted only when they contain a comma, a double quote or a line break, and double quotes inside a field are doubled.

A single-value cell that begins with =, +, -, @, a tab or a carriage return is written with a leading apostrophe, so a spreadsheet does not evaluate it as a formula. A title of =HYPERLINK("x") is exported as '=HYPERLINK("x"). Multi-value cells are joined without this check.

The CSV does not carry the description, the remediation, the CVSS vector, the tactic ids, the test category or the related findings. SARIF carries all of these except the related findings.

SARIF

The file is a SARIF 2.1.0 log with $schema set to the OASIS 2.1.0 schema URL and a single entry in runs.

The tool

runs[0].tool.driver has name set to Pentr, and version and semanticVersion both set to the version of the installed pentr-agent distribution. If the server cannot read that distribution's metadata, both are 0.0.0.

Rules

There is one rule per finding type present in the run. A finding's type is the first keyword category its text matches, from the sixteen listed in Severity and taxonomy, or finding when it matches none. The type comes from the finding's words, not from its ATT&CK or WSTG ids.

Property Value
id pentr/ followed by the type, for example pentr/sql_injection.
name The type in CamelCase, for example SqlInjection.
shortDescription.text The type with spaces, first letter capitalised, for example Sql injection.
properties.tags security, then external/cwe/cwe-<n> for every CWE id.
relationships One entry per CWE id, targeting that id in the CWE tool component with kind relevant. Absent when there are no CWE ids.

A rule's CWE ids are those of the first finding of that type in export order. Other findings of the same type can have more CWE ids; their own cwe property lists them.

Results

There is one result per finding, in export order.

Property Value
ruleId, ruleIndex The finding's rule and its position in rules.
level The severity collapsed to a SARIF level, below.
message.text The title, then : and the description. The title alone if the description is empty.
locations One location. physicalLocation.artifactLocation.uri and a logicalLocations entry of kind host both hold the affected asset.
partialFingerprints pentr/findingId, the finding's UUID.
properties The fields in the next table.

SARIF has three levels and Pentr has five severities:

Severity level
critical error
high error
medium warning
low note
info note

The original severity is kept in properties.severity. The result's properties:

Property Content
severity The five-value severity.
cvss_score The score, or null.
cvss_vector The vector, or null.
cve CVE ids.
cwe Derived CWE ids.
attack_technique_ids ATT&CK technique ids.
attack_tactic_ids ATT&CK tactic ids.
wstg_ids WSTG ids; an empty list when there are none.
framework The engagement's framework slug, for example iso27001.
control_ids The framework control ids the mapper assigned at download time.
phase The phase the finding was added in.
status The finding's status.
nist_test_category The NIST SP 800-115 test category.
remediation The remediation text.
artifact_sha256 SHA-256 hashes of the sealed artifacts linked to the finding.

Run properties

Property Content
automationDetails.id The engagement id.
properties.engagement_id The engagement id.
properties.framework The framework slug.
properties.targets The engagement's targets.
properties.scope_in The in-scope list.
properties.scope_out The out-of-scope list.
properties.evidence_integrity sealed, manifest_sha256, chain_head, entry_count, algorithm, signature_algorithm, signing_key_id, signed_at, sealed_at and note.

evidence_integrity holds the same values as the PDF's evidence-integrity section, including its note text for an unsealed run or an unreadable manifest; on a sealed run with a readable manifest, note is null.

invocations holds one entry when the engagement has a start or completion time, with startTimeUtc and endTimeUtc for whichever exist. executionSuccessful is true in every case. It does not reflect how the run ended; Sealing describes the endings a completed run can have.

Last updated 2026-09-22