Vectasec · Guides
Compliance, reports and alerts
Attest compliance controls, export OSCAL, CSV, CycloneDX SBOM and VEX, and route new Vectasec findings to Slack, Teams, Jira, webhooks, email or a SIEM.
On this page
Vectasec turns scan results into compliance status for each control, reports you can download, and alerts sent to the tools your team already watches. All three come from the findings and observations stored for your tenant.
Compliance status and attestations#
GET /compliance/{framework} returns each control with its status, the ids of failing findings (failing_finding_ids) and of not-assessable findings (unknown_finding_ids), plus a summary count per status. Framework ids are PCI_DSS_4_0_1, NIS2, DORA, HIPAA and MCP_SPEC_2025_11_25.
A scan on its own never produces pass. A control with an open, assessed failing finding is fail, and any other control stays unknown. A control reaches pass only when a person attests to it, on the console's Compliance page or through the API with a signed-in user's Supabase access token:
curl -X POST "http://127.0.0.1:8000/compliance/PCI_DSS_4_0_1/7.2.5/attest" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope": "Service accounts on the payments Kafka and RabbitMQ clusters, Q3 2026 review",
"note": "Reviewed with the platform team",
"expires_at": "2026-12-31T00:00:00Z"
}'
scopeis required: what you attested, over which systems and period.noteandexpires_atare optional.- The actor must be a signed-in user (a user uuid) with the analyst or editor role or higher.
- The attestation, the recomputed status and an audit entry are written in one transaction. The response carries the control's new
status. - Expired attestations are ignored, and an open, assessed failing finding overrides an attestation.
Export reports#
Any tenant member, including viewers, can export. In the console, the Compliance page offers OSCAL, CSV and the summary; the Supply chain page offers SBOM, VEX and the licensing panel.
Reports are built from current data on each request. When a tenant has more than 20000 findings, the OSCAL, CSV and summary reports return 413 rather than a truncated document.
SBOM and VEX#
The SBOM (application/vnd.cyclonedx+json; version=1.6) is read from the running systems, not from a build manifest.
- Only components with a version appear. A component carries a PURL when OSV's Bitnami index covers the product and a CPE when a verified NVD CPE exists. Kong and Pulsar have no PURL; Valkey has no CPE.
- The phase in
metadata.lifecyclesisoperationswhen every component came from an authenticated connector, anddiscoverywhen your estate includes any service found by a network probe. - Kafka Connect plugins appear as components with the version each plugin reports; a plugin that reports no version is left out. RabbitMQ and Kong plugins are recorded by name only in the resource inventory, because those APIs return no plugin versions, so they do not appear in the SBOM.
- The
vulnerabilitiessection lists the unresolved advisories Vectasec filed from OSV, NVD and its curated CVE pack.
In the VEX document, each finding's status sets the analysis state:
- An open or accepted finding is
in_triage. - A suppressed finding is
not_affected, with the suppression's verbatim reason and its lapse date when it has one. If no active suppression still matches, it is published asin_triage. - A resolved finding is
resolved. - Not-assessable findings, and findings marked triaged or in progress, are withheld. The number withheld is published in the metadata property
vectasec:vex-withheld-not-assessable.
When one advisory affects several components, the merged entry carries the least reassuring state.
GET /licensing lists each running product version with its licence identifiers, OSI approval and source. Terms depend on the version: Redis 7.2 is BSD-3-Clause, 7.4 is source-available (SSPL or RSALv2), and 8.0 adds AGPL-3.0 as a third choice. A product outside the licence table, or a version that was inferred rather than read, is reported as unknown instead of guessed. Licences are reported, never filed as findings.
Vulnerability and end-of-support checks#
After each scan that the engine runs itself, it checks reported versions against two live feeds:
An unreachable feed, or an exhausted NVD budget, files a coverage-gap finding (SUPPLY.OSV.NOT_ASSESSABLE or SUPPLY.NVD.NOT_ASSESSABLE) naming what went unchecked. A feed problem never fails a scan. On an air-gapped engine, set VECTASEC_OSV_DISABLED and VECTASEC_NVD_DISABLED; a disabled feed files no gap findings. See Configuration.
End-of-support rules run offline from a curated dataset with a source URL for every branch date. SUPPLY.LIFECYCLE.END_OF_LIFE (high) fires past the published date and SUPPLY.LIFECYCLE.APPROACHING_EOL (medium) within 180 days by default. An unknown product or branch, an unreadable version, or an inferred version gives SUPPLY.LIFECYCLE.NOT_ASSESSABLE instead.
Route alerts#
An alert needs a destination and a routing rule that points at it. Creating or deleting either requires the admin or owner role. Use the console under Settings, then Integrations, or the API.
Add a destination#
Send POST /integrations with type, name and config, plus an optional enabled (default true; a disabled destination receives nothing). Posting the same type and name again updates it, and an empty secret field keeps the stored value.
Webhook URLs, the HMAC secret, the Jira token and the SIEM URL and token are stored in Supabase Vault; the config row keeps only non-secret fields. POST /integrations/{id}/test sends a real test message through the same sender a scan uses and returns ok with any error.
Add a routing rule#
{
"integration_id": "REPLACE_WITH_INTEGRATION_ID",
"name": "High and critical broker findings",
"match": {
"min_severity": "high",
"connector_types": ["kafka", "rabbitmq"],
"rule_prefixes": ["KAFKA.", "RABBITMQ."],
"notify_on": ["new_findings"]
}
}
Send this to POST /routing-rules. integration_id is required; name and enabled (default true) are optional. Every key inside match is optional, and a match of {} routes everything. min_severity is inclusive, connector_types limits the rule to those connection types, rule_prefixes match the start of the rule id, and notify_on takes new_findings, scan_failed or both (the default). The console's rule form sets a minimum severity and, optionally, one connector type; use the API for rule_prefixes, notify_on and rule names.
- New means first seen in this scan and not suppressed, so rescans do not re-alert on known findings.
- A rule sends one message per scan when at least one new finding matches. Slack, Teams, email and Jira list up to 10 findings; webhook and SIEM payloads carry all of them.
scan_failedfires when the queue worker gives up on a scan: after its retries run out, or at once when a retry cannot help, such as rejected credentials or a configuration error.- A failed delivery never fails a scan. Every attempt is recorded in
notification_deliveriesand shown in the console. - Rules cannot be edited. Delete one with
DELETE /routing-rules/{id}and create it again.
Verify webhook signatures#
The webhook body carries source, event (new_findings, scan_failed or test), tenant_id, scan_id, connection, findings and error. With hmac_secret set, each request has an X-VectaSec-Signature header of sha256= followed by the hex HMAC-SHA256 of the raw body. Verify it before parsing:
import hashlib
import hmac
def is_valid(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header or "")
Private-network destinations#
These rules apply to the HTTP destinations: Slack, Teams, webhook, Jira and SIEM. The URL must be http or https. Destinations that resolve to link-local (including cloud metadata), multicast or unspecified addresses are always refused. Private and loopback addresses are refused unless the engine sets VECTASEC_ALLOW_PRIVATE_NOTIFY_TARGETS=1. The check runs at send time, so a refused destination shows up as a failed test or delivery.
Next steps#
- Findings, evidence and compliance: how findings map to controls.
- Configuration: feed switches and SMTP settings.
- Security model: how destination secrets are protected.
- CLI and API reference: every route on this page.