The stable native JSON contract is metadata.schema_version: 2. It separates execution metadata, severity and source summaries, finding dispositions, findings, coverage, imports, and the hosted release verdict.
Validated examples
Both examples are emitted by the current JSON renderer during contract generation.
{
"metadata": {
"schema_version": 2,
"fingerprint_algorithm": "fendix/v2",
"target": "https://staging.example.com",
"started_at": "2026-10-03T09:00:00Z",
"duration": "1.2s",
"version": "v3.7.0",
"mode": "blackbox",
"endpoints_scanned": 1,
"active_probes": false
},
"summary": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
},
"sources": {
"blackbox": 0,
"whitebox": 0,
"correlated": 0
},
"total": 0,
"decisions": {
"total": 0,
"confirmed": 0,
"blocking": 0,
"warning": 0,
"informational": 0
},
"findings": []
}{
"metadata": {
"schema_version": 2,
"fingerprint_algorithm": "fendix/v2",
"target": "https://staging.example.com",
"started_at": "2026-10-03T09:00:00Z",
"duration": "2.4s",
"version": "v3.7.0",
"mode": "hybrid",
"endpoints_scanned": 12,
"active_probes": false,
"scanner_status": [
{
"name": "semgrep",
"state": "ok"
},
{
"name": "dast",
"state": "ok"
},
{
"name": "pip",
"state": "skipped",
"reason": "dependency_missing",
"detail": "required manifest was not delivered"
}
],
"coverage": {
"contract_version": 1,
"strict": true,
"configured_complete": false,
"gaps": [
"pip"
],
"limitations": [],
"required_analyzers": [
"semgrep",
"dast",
"pip"
],
"required_gaps": [
"pip"
],
"retried": []
},
"policy_version": "v2",
"release_decision": "incomplete",
"coverage_state": "incomplete",
"decision_policy_version": "v2"
},
"summary": {
"critical": 0,
"high": 1,
"medium": 0,
"low": 0,
"info": 0
},
"sources": {
"blackbox": 0,
"whitebox": 1,
"correlated": 0
},
"total": 1,
"decisions": {
"total": 1,
"confirmed": 0,
"blocking": 0,
"warning": 1,
"informational": 0
},
"findings": [
{
"id": "SEC-001",
"fingerprint": "1dcbb4264cbed08eb4a54e6f509a724445801f92",
"fingerprint_v1": "faad9eebeafb6050752d685b1670fc5be0266f1b",
"rule_id": "python.auth.missing",
"sink": "return user_record",
"symbol": "users.get",
"title": "Missing authentication on user data endpoint",
"severity": "HIGH",
"source": "whitebox",
"category": "auth",
"endpoint": "app/users.py:42",
"evidence": "GET /api/users/{id} reaches users.get without an authentication guard",
"fix": "Require authentication before returning user data.",
"references": [
"CWE-306"
],
"confidence": "MEDIUM",
"line": null,
"source_tier": "tree_sitter_sidecar",
"status": "WARN",
"confidence_score": 68,
"confidence_band": "MEDIUM",
"decision_reason": "Evidence does not meet the enforced blocking requirement.",
"decision_policy": "enforced",
"auth_expectation": "required"
}
]
}In the decision-aware example, SEC-001 remains HIGH → WARN. The separate missing required pip/SCA evidence makes release_decision equal incomplete.
Field reference
Required and optional status comes directly from the formal Draft 7 schema. Nullable is shown in the type when null is allowed.
Report
Schema for Fendix scan output produced by `fendix scan --format json`. Current reports carry metadata.schema_version 2. Additive fields do not require a version bump; incompatible shape or semantic changes do. Archived pre-versioned and schema-version 1 reports remain readable. See docs/schema.md.
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| decisions | StatusCounts | No — omitted when unavailable | — | Finding-disposition counts; absent in compatible reports produced before this additive block existed. |
| findings | array<Finding> | Yes | — | Correlated and finalized security findings; always an array, including when empty. |
| metadata | ScanMetadata | Yes | — | Execution, version, coverage, import, and release-decision metadata for the report. |
| sources | SourceCounts | Yes | — | Counts findings by native source family. |
| summary | SeverityCounts | Yes | — | Counts findings by intrinsic severity. |
| total | integer | Yes | min 0 | Total number of rendered findings. |
ConfidenceReason
One scoring rule's contribution to a confidence score. `code` is the stable machine-readable identity a consumer matches on; `text` is human wording and is free to be reworded. The `delta` values of a finding's confidence_breakdown sum to its confidence_score.
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| ConfidenceReason.code | string | Yes | — | Stable machine identifier for one confidence rule. |
| ConfidenceReason.delta | integer | Yes | — | Signed contribution to confidence_score. |
| ConfidenceReason.text | string | Yes | — | Human wording; consumers must not parse it as an identifier. |
Coverage
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| Coverage.configured_complete | boolean | Yes | — | Whether configured engine analyzers delivered without engine gaps. |
| Coverage.contract_version | integer | Yes | min 1 | Published contract version value in the Coverage contract; use the declared type and absence rules rather than parsing display text. |
| Coverage.gaps | array<string> | Yes | — | Published gaps value in the Coverage contract; use the declared type and absence rules rather than parsing display text. |
| Coverage.limitations | array<string> | Yes | — | Published limitations value in the Coverage contract; use the declared type and absence rules rather than parsing display text. |
| Coverage.required_analyzers | array<string> | Yes | — | Published required analyzers value in the Coverage contract; use the declared type and absence rules rather than parsing display text. |
| Coverage.required_gaps | array<string> | Yes | — | Named required analyzers that did not satisfy the strict requirement. |
| Coverage.retried | array<string> | Yes | — | Published retried value in the Coverage contract; use the declared type and absence rules rather than parsing display text. |
| Coverage.strict | boolean | Yes | — | Published strict value in the Coverage contract; use the declared type and absence rules rather than parsing display text. |
DependencyRef
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| DependencyRef.ecosystem | string | No — omitted when unavailable | — | Published ecosystem value in the DependencyRef contract; use the declared type and absence rules rather than parsing display text. |
| DependencyRef.manifest | string | No — omitted when unavailable | — | Published manifest value in the DependencyRef contract; use the declared type and absence rules rather than parsing display text. |
| DependencyRef.package | string | No — omitted when unavailable | — | Published package value in the DependencyRef contract; use the declared type and absence rules rather than parsing display text. |
| DependencyRef.version | string | No — omitted when unavailable | — | Published version value in the DependencyRef contract; use the declared type and absence rules rather than parsing display text. |
Finding
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| Finding.affected_endpoints | array<string> | No — omitted when unavailable | — | Published affected endpoints value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.applicability | string | No — omitted when unavailable | applicable | evidence_against | Published applicability value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.auth_expectation | string | No — omitted when unavailable | public | required | Published auth expectation value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.category | string | Yes | minLength 1 | Published category value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.confidence | string | Yes | HIGH | MEDIUM | LOW | Producer/correlation confidence retained for compatibility. |
| Finding.confidence_band | string | No — omitted when unavailable | HIGH | MEDIUM | LOW | HIGH, MEDIUM, or LOW band derived from confidence_score. |
| Finding.confidence_breakdown | array<ConfidenceReason> | No — omitted when unavailable | — | Machine-readable scoring contributions whose deltas reconstruct confidence_score. |
| Finding.confidence_reasons | array<string> | No — omitted when unavailable | — | Published confidence reasons value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.confidence_score | integer | No — omitted when unavailable | min 0 · max 100 | Deterministic 0–100 score from the current confidence policy. |
| Finding.corroborating_tools | array<string> | No — omitted when unavailable | — | Normalized external tool identities that prove cross-tool corroboration. |
| Finding.cross_tool_corroborated | boolean | No — omitted when unavailable | — | True only when an independent tool reported the same normalized weakness at the same normalized location. |
| Finding.decision_policy | string | No — omitted when unavailable | enforced | relaxed | Published decision policy value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.decision_reason | string | No — omitted when unavailable | — | Published decision reason value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.dependency | DependencyRef | No — omitted when unavailable | — | Published dependency value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.endpoint | string | Yes | — | Published endpoint value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.evidence | string | Yes | — | Bounded human-readable observation retained for review. |
| Finding.fingerprint | string | No — omitted when unavailable | — | Long-lived semantic identity in the namespace named by fingerprint_algorithm. |
| Finding.fingerprint_v1 | string | No — omitted when unavailable | — | Retired v1 identity carried only as a migration bridge. |
| Finding.fix | string | Yes | — | Published fix value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.id | string | Yes | ^SEC-[0-9]+$ | Run-local positional SEC identifier; it is not long-lived identity. |
| Finding.independent_signals | array<string> | No — omitted when unavailable | — | Published independent signals value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.line | string | null | Yes | — | Published line value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.occurrences | array<Occurrence> | No — omitted when unavailable | — | Every distinct security occurrence this finding presents, one per (endpoint, occurrence fingerprint). Identity, .fendix-ignore matching, baseline matching and lifecycle tracking act on occurrences; the finding is a presentation group. The finding's own fingerprint is its primary occurrence's and always appears here. Absent on reports from engines that predate the field. |
| Finding.policy_override | boolean | No — omitted when unavailable | — | Published policy override value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.proven_path | boolean | No — omitted when unavailable | — | Published proven path value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.reachable | boolean | No — omitted when unavailable | — | Published reachable value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.references | array<string> | Yes | — | Published references value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.route | Route | No — omitted when unavailable | — | Published route value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.route_confirmed | boolean | No — omitted when unavailable | — | Published route confirmed value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.rule_id | string | No — omitted when unavailable | — | Stable analyzer rule or check identity when the producer supplies one. |
| Finding.secret | SecretRef | No — omitted when unavailable | — | Published secret value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.self_evident_signals | array<string> | No — omitted when unavailable | — | Published self evident signals value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.severity | string | Yes | CRITICAL | HIGH | MEDIUM | LOW | INFO | Intrinsic impact if the condition is real; it is not the disposition or release decision. |
| Finding.sink | string | No — omitted when unavailable | — | Published sink value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.source | string | Yes | blackbox | whitebox | correlated | imported | Finding source family, including the explicit imported provenance boundary. |
| Finding.source_tier | string | No — omitted when unavailable | native_go | tree_sitter_sidecar | semgrep_shim | Published source tier value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.status | string | No — omitted when unavailable | BLOCK | WARN | INFO | Finding disposition: BLOCK, WARN, or INFO. |
| Finding.symbol | string | No — omitted when unavailable | — | Published symbol value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.taint_chain | array<TaintLink> | No — omitted when unavailable | — | Published taint chain value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
| Finding.title | string | Yes | minLength 1 | Published title value in the Finding contract; use the declared type and absence rules rather than parsing display text. |
ImportedTool
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| ImportedTool.corroborated | integer | No — omitted when unavailable | min 0 | Imported results collapsed into native representatives by strong cross-tool correlation. |
| ImportedTool.no_location | integer | No — omitted when unavailable | min 0 | Published no location value in the ImportedTool contract; use the declared type and absence rules rather than parsing display text. |
| ImportedTool.results | integer | Yes | min 0 | Published results value in the ImportedTool contract; use the declared type and absence rules rather than parsing display text. |
| ImportedTool.suppressed | integer | No — omitted when unavailable | min 0 | Published suppressed value in the ImportedTool contract; use the declared type and absence rules rather than parsing display text. |
| ImportedTool.tool | string | Yes | — | Published tool value in the ImportedTool contract; use the declared type and absence rules rather than parsing display text. |
| ImportedTool.version | string | No — omitted when unavailable | — | Published version value in the ImportedTool contract; use the declared type and absence rules rather than parsing display text. |
Occurrence
One security occurrence: where it is, and its own fendix/v2 fingerprint, computed from that occurrence alone before any grouping.
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| Occurrence.endpoint | string | Yes | — | Published endpoint value in the Occurrence contract; use the declared type and absence rules rather than parsing display text. |
| Occurrence.fingerprint | string | Yes | — | Published fingerprint value in the Occurrence contract; use the declared type and absence rules rather than parsing display text. |
Route
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| Route.file | string | No — omitted when unavailable | — | Published file value in the Route contract; use the declared type and absence rules rather than parsing display text. |
| Route.handler | string | No — omitted when unavailable | — | Published handler value in the Route contract; use the declared type and absence rules rather than parsing display text. |
| Route.line | integer | No — omitted when unavailable | min 0 | Published line value in the Route contract; use the declared type and absence rules rather than parsing display text. |
| Route.method | string | No — omitted when unavailable | — | Published method value in the Route contract; use the declared type and absence rules rather than parsing display text. |
| Route.pattern | string | No — omitted when unavailable | — | Published pattern value in the Route contract; use the declared type and absence rules rather than parsing display text. |
ScanMetadata
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| ScanMetadata.active_probes | boolean | Yes | — | Whether opt-in active probes were enabled. |
| ScanMetadata.checks_run | array<string> | No — omitted when unavailable | — | Check selectors recorded for the run. |
| ScanMetadata.coverage | Coverage | No — omitted when unavailable | — | Coverage contract v1 statement for configured analyzer execution. |
| ScanMetadata.coverage_state | string | No — omitted when unavailable | complete | incomplete | unknown | Hosted release-coverage state, separate from finding disposition. |
| ScanMetadata.decision_policy_version | string | No — omitted when unavailable | — | Hosted release-decision policy version. |
| ScanMetadata.decision_rationale | object | No — omitted when unavailable | — | Opaque structured rationale supplied by the hosted decision layer. |
| ScanMetadata.duration | string | Yes | — | Human-readable elapsed duration. |
| ScanMetadata.endpoints_discovered | integer | No — omitted when unavailable | min 0 | Endpoints found before the maximum-endpoint cap. |
| ScanMetadata.endpoints_scanned | integer | Yes | min 0 | Endpoints retained and scanned after limits. |
| ScanMetadata.endpoints_truncated | boolean | No — omitted when unavailable | — | True when the endpoint cap omitted discovered endpoints. |
| ScanMetadata.fingerprint_algorithm | string | No — omitted when unavailable | — | Identity namespace used for finding fingerprints in this report. |
| ScanMetadata.imports | array<ImportedTool> | No — omitted when unavailable | — | Per-external-tool accounting for imported SARIF results. |
| ScanMetadata.mode | string | Yes | blackbox | whitebox | hybrid | import | Executed scan mode. |
| ScanMetadata.policy_version | string | No — omitted when unavailable | — | Finding-decision policy version used by the engine. |
| ScanMetadata.release_decision | string | No — omitted when unavailable | pass | warn | block | incomplete | Hosted release verdict passed through for re-rendering. |
| ScanMetadata.scanner_status | array<ScannerStatus> | No — omitted when unavailable | — | Per-analyzer terminal execution outcomes. |
| ScanMetadata.schema_version | integer | No — omitted when unavailable | min 1 | JSON report contract version. Current stable reports write 2; missing means a pre-versioned archive. |
| ScanMetadata.started_at | string | Yes | date-time | UTC-compatible scan start timestamp. |
| ScanMetadata.target | string | Yes | — | Target supplied to the scan; treat it as data, not as a stable identifier. |
| ScanMetadata.version | string | Yes | — | Fendix engine version that wrote the report. |
ScannerStatus
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| ScannerStatus.attempts | integer | No — omitted when unavailable | min 2 | Published attempts value in the ScannerStatus contract; use the declared type and absence rules rather than parsing display text. |
| ScannerStatus.detail | string | No — omitted when unavailable | — | Published detail value in the ScannerStatus contract; use the declared type and absence rules rather than parsing display text. |
| ScannerStatus.name | string | Yes | — | Published name value in the ScannerStatus contract; use the declared type and absence rules rather than parsing display text. |
| ScannerStatus.reason | string | No — omitted when unavailable | not_applicable | diff_unchanged | disabled_by_flag | disabled_offline | dependency_missing | unsupported_target | network_error | timeout | execution_error | malformed_output | truncated_output | input_error | no_endpoints | Closed machine-readable reason for a skipped or failed analyzer. |
| ScannerStatus.state | string | Yes | ok | skipped | failed | Raw terminal analyzer state: ok, skipped, or failed. |
SecretRef
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| SecretRef.file | string | No — omitted when unavailable | — | Published file value in the SecretRef contract; use the declared type and absence rules rather than parsing display text. |
| SecretRef.identifier | string | No — omitted when unavailable | — | Published identifier value in the SecretRef contract; use the declared type and absence rules rather than parsing display text. |
SeverityCounts
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| SeverityCounts.critical | integer | Yes | min 0 | Published critical value in the SeverityCounts contract; use the declared type and absence rules rather than parsing display text. |
| SeverityCounts.high | integer | Yes | min 0 | Published high value in the SeverityCounts contract; use the declared type and absence rules rather than parsing display text. |
| SeverityCounts.info | integer | Yes | min 0 | Published info value in the SeverityCounts contract; use the declared type and absence rules rather than parsing display text. |
| SeverityCounts.low | integer | Yes | min 0 | Published low value in the SeverityCounts contract; use the declared type and absence rules rather than parsing display text. |
| SeverityCounts.medium | integer | Yes | min 0 | Published medium value in the SeverityCounts contract; use the declared type and absence rules rather than parsing display text. |
SourceCounts
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| SourceCounts.blackbox | integer | Yes | min 0 | Published blackbox value in the SourceCounts contract; use the declared type and absence rules rather than parsing display text. |
| SourceCounts.correlated | integer | Yes | min 0 | Published correlated value in the SourceCounts contract; use the declared type and absence rules rather than parsing display text. |
| SourceCounts.whitebox | integer | Yes | min 0 | Published whitebox value in the SourceCounts contract; use the declared type and absence rules rather than parsing display text. |
StatusCounts
v0.24 decision summary. Additive; not in the root `required` set.
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| StatusCounts.blocking | integer | Yes | min 0 | Published blocking value in the StatusCounts contract; use the declared type and absence rules rather than parsing display text. |
| StatusCounts.confirmed | integer | Yes | min 0 | Published confirmed value in the StatusCounts contract; use the declared type and absence rules rather than parsing display text. |
| StatusCounts.informational | integer | Yes | min 0 | Published informational value in the StatusCounts contract; use the declared type and absence rules rather than parsing display text. |
| StatusCounts.total | integer | Yes | min 0 | Published total value in the StatusCounts contract; use the declared type and absence rules rather than parsing display text. |
| StatusCounts.warning | integer | Yes | min 0 | Published warning value in the StatusCounts contract; use the declared type and absence rules rather than parsing display text. |
TaintLink
| JSON path | Type | Required | Values / constraints | Meaning |
|---|---|---|---|---|
| TaintLink.expr | string | Yes | — | Published expr value in the TaintLink contract; use the declared type and absence rules rather than parsing display text. |
| TaintLink.file | string | Yes | — | Published file value in the TaintLink contract; use the declared type and absence rules rather than parsing display text. |
| TaintLink.line | integer | Yes | min 0 | Published line value in the TaintLink contract; use the declared type and absence rules rather than parsing display text. |