Skip to content

Overview

Quorum (quorum-sec-scan, v0.8.3) is a CLI/Docker consensus security scanning tool: it orchestrates a pool of 12 open-source security scanners (Trivy, Grype, Checkov, KICS, Terrascan, tfsec, Regula, Conftest, Dockle, Kubescape, Polaris, kube-score) over a target, normalizes every finding into a canonical model, resolves vulnerability aliases, correlates equivalent findings across tools, and emits a single report that tells you how many and which scanners detected each problem — plus a confidence score derived from that consensus. Quorum is not yet another scanner: it is the lightweight correlation + consensus layer on top of the tools you already trust, designed to run inside a CI/CD pipeline and block a build via exit code. An opt-in advisory layer (--advice) can additionally attach curated remediation, OWASP references, and — when explicitly enabled — AI recommendations; it is presentation-only and never alters the deterministic core. This document describes the goal, the problem solved, the target audience, personas, benefits, differentiators, and use cases.

Code references verified for this document: README.md, DESIGN.md, cmd/quorum/root.go, cmd/quorum/scan.go, internal/adapter/, crosswalk/.


1. System goal

Quorum's goal is to turn multiple incompatible scanner reports into a single consolidated, prioritizable report, in which each finding carries consensus evidence (how many and which engines detected it) and a computed confidence score, in a deterministic and CI/CD-actionable way.

Operationally, Quorum delivers:

  1. Orchestration — runs the supported scanners against the target in parallel, with a per-scanner timeout.
  2. Normalization — converts each tool's output into a canonical model.Finding (a single severity scale, PURLs for packages, AVD/CIS/category for controls).
  3. Alias resolution — unifies CVE-… and GHSA-… of the same bug (only for VULN) via local aliases → local cache → OSV.dev (CVE preferred).
  4. Correlation — groups equivalent findings by a deterministic, type-specific correlationKey.
  5. Consensus — computes detectionCount and confidence (0..1) for each group.
  6. Report — emits SARIF (primary), JSON, or XML, always with the per-scanner status.
target → normalize → resolve aliases → correlate → score → report (SARIF/JSON/XML)

Pipeline per DESIGN.md §3 and the stage-by-stage description in README.md.


2. Problem solved

Different scanners find overlapping but not identical problems and report them in incompatible formats. Whoever runs three tools gets three reports, duplicated findings, and no signal about which findings are corroborated. This leads to concrete pains:

Pain without Quorum How Quorum solves it
N scanners → N reports in distinct formats Single canonical model (model.Finding) + one consolidated report
Duplicated findings (the same CVE in Trivy and Grype) Correlation by deterministic correlationKey + dedup
GHSA-… (Grype) and CVE-… (Trivy) treated as different bugs Alias Resolver unifies to the canonical form (CVE preferred)
Identical IaC misconfig in Checkov/KICS/Terrascan/tfsec/Regula with no convergence signal Crosswalk rule → canonical control (AVD hub) correlates across engines
K8s posture repeated in Kubescape/Polaris/kube-score with no consolidation Crosswalk k8s.yaml (Kubescape C-#### hub) correlates the three engines
No corroboration signal across tools detectionCount + detectedBy + confidence per finding
"0 findings" read as "it's safe" Explicit per-scanner status (ran/skipped/unavailable/error/timeout)
Manual temporal dedup across CI runs partialFingerprints["quorum/v1"] = sha256(correlationKey) in SARIF
Scanner images/binaries as a supply chain vector Keyless signed distribution (cosign) + SLSA build-provenance attestation + attested SPDX SBOM

Guiding principle: false split > false merge. When in doubt, Quorum keeps findings separate and marks them unmapped — a wrong merge hides risk. (See DESIGN.md §6, "No-match rule".)

What the problem is NOT (scope)

Quorum does not aim to be:

  • a new scanner (it reuses existing OSS scanners);
  • a runtime security solution (stream model, out of scope — a future proposal on the roadmap);
  • a platform with a web dashboard, daemon, or persistent service.

The advisory layer does not change this scope: it is opt-in, presentation-only, and off by default. Without --advice, output is byte-identical, the deterministic core has no AI, and any AI recommendation is strictly opt-in (see §7 Differentiators and §9 Assumptions).


3. Target audience

Quorum is aimed at teams that already operate OSS scanners and need to consolidate and prioritize results within automated pipelines:

  • AppSec / DevSecOps teams that maintain security gates in CI/CD.
  • Platform / developer-productivity teams that standardize security tooling across repositories.
  • Cloud/IaC engineers who validate Terraform and K8s manifests across clouds (AWS/Azure/GCP) before apply.
  • Tech Leads / maintainers who need a reliable signal (consensus) to decide what blocks a merge.
  • Compliance auditors who need traceable evidence (AVD/CIS canonical controls, per-scanner status, stable fingerprints).

Quorum is CLI/Docker only: there is no web frontend, relational database, or HTTP REST API. The deterministic core has no AI/LLM; an opt-in advisory layer (local or remote) can be enabled but is off by default (see §7 Differentiators and §9 Assumptions). The audience is therefore technical and automation-centric.


4. Personas

Persona Main goal How they use Quorum Success metric
AppSec / DevSecOps Engineer Cut noise and prioritize what's real Configures --fail-on, --min-severity, .quorumignore; analyzes confidence and detectionCount; optionally --advice for remediation Fewer false positives at the gate; corroborated findings prioritized
Tech Lead / Maintainer Decide what blocks the merge without becoming a bottleneck Uses the PR gate (exit code 1) and the per-severity summary on stderr PRs blocked only when there is corroborated risk
Compliance Auditor Traceable evidence mapped to controls Reads SARIF/JSON with partialFingerprints, canonical controls (AVD/CIS), and per-scanner status Reproducible audit trail; suppressions always logged
Platform / CI/CD Standardize the scan across N repositories without installing scanners Uses the :full image or the GitHub Action composite (cosign-verified; socket auto-mounted on type: image) Repository onboarding with no local tooling install
Cloud/IaC Engineer Validate multi-cloud Terraform/K8s before apply quorum scan . --type repo / --type k8s, crosswalk rule→control (AWS/Azure/GCP + K8s) IaC misconfig and posture correlated across multiple engines

5. Benefits

  • Signal instead of noise. Consensus (detectionCount + confidence) separates corroborated findings from isolated detections; the raw count is not confidence — the formula weighs engine diversity, severity, and authoritative confirmation (DESIGN.md §9).
  • Consensus beyond SCA. Cross-corroboration is no longer only about vulnerabilities: it covers multi-cloud IaC misconfig (Checkov × KICS × Terrascan × tfsec × Regula × Trivy) and Kubernetes posture (Kubescape × Polaris × kube-score), via a crosswalk derived from real output.
  • One report, multiple formats. SARIF (primary, for GitHub code scanning/DefectDojo), JSON (for processing), and XML (legacy/JUnit-like pipelines).
  • Optional telemetry. --metrics writes metrics in Prometheus textfile format; --log-format json emits structured progress logs (one object per line) on stderr.
  • Free temporal dedup. partialFingerprints["quorum/v1"] lets external tools recognize the same finding across runs.
  • Operational resilience. A missing scanner becomes unavailable and is skipped — the scan never fails just because a tool is not installed. Timeout/OOM are distinguished from "not installed" via a version probe. DoS caps limit output (QUORUM_MAX_OUTPUT_BYTES, 512 MiB) and target size (QUORUM_MAX_TARGET_BYTES, 20 GiB).
  • Honesty about coverage. "0 findings is not proof of safety" is part of the product: the per-scanner status makes explicit whether anything actually ran.
  • Direct CI gate. Exit code: 0 = ok / no finding reached --fail-on; 1 = gate triggered; 2 = usage/runtime error.
  • Opt-in advisory layer. --advice attaches curated remediation templates + OWASP references (deterministic, no model) and, optionally, a natural-language recommendation from a local or remote provider — always labeled "AI-generated, advisory only". It is presentation-only: it never touches correlationKey, fingerprint, confidence, aggregated severity, or the fail-on gate.
  • Verifiable supply chain. Images and binaries keyless-signed with cosign (OIDC) + SLSA build-provenance attestation + attested SPDX SBOM, verifiable at release. The knowledge pack + crosswalk also ship a SLSA build-provenance attestation each release.
  • Determinism. correlationKey and Fingerprint = sha256(correlationKey) are pure functions of the normalized data → reproducible reports.

6. Context diagram

flowchart TB
    subgraph atores["Actors and triggers"]
        dev["Dev / Tech Lead<br/>(PR)"]
        ci["CI/CD Pipeline<br/>(GitHub Action / GitLab)"]
        appsec["AppSec / DevSecOps"]
        auditor["Compliance Auditor"]
    end

    subgraph quorum["Quorum (CLI / Docker)"]
        orch["Orchestrator<br/>fan-out + timeout + probe"]
        norm["Normalization<br/>model.Finding"]
        alias["Alias Resolver<br/>(VULN)"]
        corr["Correlator<br/>correlationKey"]
        cons["Consensus<br/>detectionCount + confidence"]
        adv["Advisory layer<br/>(--advice, opt-in)"]
        rep["Reporters<br/>SARIF / JSON / XML"]
    end

    subgraph scanners["Pool of 12 OSS scanners"]
        sca["VULN<br/>trivy · grype"]
        iac["MISCONFIG / IaC<br/>trivy · checkov · kics<br/>terrascan · tfsec · regula · conftest"]
        img["IMG_HARDENING<br/>dockle"]
        k8s["K8S_POSTURE<br/>kubescape · polaris · kube-score"]
    end

    subgraph ext["External services and data"]
        osv["OSV.dev<br/>(aliases, optional)"]
        cw["Crosswalk YAML<br/>aws/azure/gcp/k8s<br/>rule → canonical control"]
        pol["Local Rego<br/>./policy (conftest)"]
        know["Knowledge pack<br/>+ OWASP corpus<br/>(--advice)"]
        llm["Advice provider<br/>local/remote (opt-in)"]
        cache[("Local cache<br/>~/.cache/quorum")]
        ghcr["GHCR<br/>signed images + SLSA + SBOM"]
    end

    subgraph consumidores["Report consumers"]
        gh["GitHub code scanning"]
        dd["DefectDojo / SIEM"]
        prom["Prometheus<br/>(--metrics)"]
        gate["Build gate (exit code)"]
    end

    dev --> ci
    ci --> orch
    appsec --> orch
    orch --> scanners
    scanners --> norm
    pol --> iac
    norm --> alias
    alias <-->|optional| osv
    alias <--> cache
    alias --> corr
    cw --> corr
    corr --> cons
    cons --> adv
    know -.->|opt-in| adv
    llm -.->|opt-in| adv
    adv --> rep
    rep --> gh
    rep --> dd
    rep --> prom
    rep --> gate
    gate --> ci
    auditor --> rep
    ghcr -.distributes.-> quorum

7. Differentiators

Differentiator What it is Where it shows in the product
Consensus + score detectionCount and confidence (0..1) per finding; confidence weighs engine diversity, severity, and authoritative confirmation properties.detectedBy/detectionCount/confidence in SARIF; DESIGN.md §9
Multi-domain consensus Cross-corroboration in VULN, multi-cloud MISCONFIG/IaC, and K8s posture — not just SCA Crosswalk aws/azure/gcp.yaml (AVD hub) and k8s.yaml (Kubescape C-#### hub) derived from real output
false split > false merge When in doubt, findings are not merged; a control with no mapping stays isolated and unmapped "No-match rule", DESIGN.md §6
Per-scanner status transparency Every report exposes ran/skipped/unavailable/error/timeout; a version probe distinguishes timeout/OOM/not-installed Summary on stderr (cmd/quorum/scan.go, printSummary); "0 findings is not proof of safety"
Deterministic correlation Per-type correlationKey + Fingerprint = sha256(correlationKey); partialFingerprints["quorum/v1"] in SARIF DESIGN.md §6, §11
Alias resolution with graceful degradation CVE/GHSA unified via OSV.dev; a network failure does not bring down the scan; --offline disables OSV; aliases.json cache with perm 0600 and schemaVersion DESIGN.md §7; cmd/quorum/scan.go
Opt-in advisory layer --advice attaches remediation + OWASP references (deterministic, DIGEST-PINNED corpus) and optional local/remote AI advice; --fix=suggest proposes a patch that must pass a verify-the-fix re-scan and never auto-applies internal/enrich, internal/rag, internal/advisor; docs/13-ia.md
Policy-as-code opt-in conftest evaluates your Rego from ./policy (or QUORUM_CONFTEST_ARGS); with no policies it is reported as error — explicit opt-in internal/adapter/conftest.go
Per-scanner passthrough QUORUM_<SCANNER>_ARGS appends arguments to the command (e.g., QUORUM_CHECKOV_ARGS --bc-api-key unlocks Prisma policies) README.md Scanners section; *-args inputs in the Action
Signed and attested supply chain :full/:slim images and binaries keyless-signed (cosign/OIDC) + SLSA build-provenance + attested SPDX SBOM; bases pinned by sha256; scanners checksum-verified; the knowledge pack + crosswalk carry their own SLSA attestation; Action composite cosign-verifies before running README.md Install/CI/CD section; release.yml, .goreleaser.yaml
Pluggable crosswalk rule → canonical control YAML (AVD/CIS); bundled at /opt/quorum/crosswalk with automatic fallback DESIGN.md §8; resolveCrosswalkDir in cmd/quorum/scan.go
Auditable baseline .quorumignore by fingerprint/correlationKey; suppressions always logged, never silently dropped README.md Baseline section; filter.Apply

8. Use cases

8.1 Pull Request gate (consensus in CI)

Block a PR when there is a corroborated finding at or above a threshold, accepting risks already triaged via baseline.

# GitHub Actions — via the composite Action (cosign-verifies the :full image)
- uses: Martinez1991/quorum-sec-scan@v0   # moving v0 tag advanced per release; pin by @<sha> in production
  with:
    target: .
    type: repo
    fail-on: high
  • [ ] Set --fail-on (e.g., high or critical).
  • [ ] Create/maintain .quorumignore for accepted risks (with a comment and date).
  • [ ] Upload the SARIF to GitHub code scanning.
  • [ ] Treat exit code 1 as the gate and 2 as a pipeline error.

8.2 Image scan (SCA / vulnerabilities)

SCA consensus over a container image, with CVE/GHSA aliases unified.

quorum scan myimage:1.2.3 --type image --scanners trivy,grype --fail-on critical
  • [ ] Use trivy + grype for VULN corroboration.
  • [ ] Keep --offline if the environment cannot reach OSV.dev (uses local aliases + cache).
  • [ ] For a local image via :full/Action, share the Docker socket (auto-mounted on type: image in the Action) — without it, the scan falls back to a pull and reports a false zero.

8.3 Infrastructure as Code (IaC / multi-cloud misconfig)

Misconfig consensus over Terraform (AWS/Azure/GCP), with SARIF for code scanning.

quorum scan . --type repo --format sarif -o quorum.sarif
  • [ ] Leverage consensus across Checkov, KICS, Terrascan, tfsec, Regula, and Trivy (tfsec emits native AVD and auto-correlates with Trivy).
  • [ ] Ensure the crosswalk (crosswalk/{aws,azure,gcp}.yaml) maps the rules to the canonical control (AVD).
  • [ ] Optional: add your Rego in ./policy to trigger conftest (policy-as-code).
  • [ ] Optional: add --advice to attach remediation + OWASP references per finding (deterministic; no data leaves the host).
  • [ ] Remember: a rule with no mapping stays unmapped (it is not guessed).

8.4 Kubernetes posture (K8s posture, multi-engine)

Posture evaluation over K8s manifests, with consensus across three engines.

quorum scan ./k8s --type k8s --format json -o quorum.json
  • [ ] Use --type k8s to trigger kubescape, polaris, and kube-score (crosswalk k8s.yaml, Kubescape C-#### hub).
  • [ ] The crosswalk covers privilege-escalation, privileged, non-root, CPU/memory limits, probes, read-only-fs, linux-hardening, service-account automount, network-policy, host-network, host-PID/IPC, capabilities, and secrets.
  • [ ] RBAC stays single-engine (Kubescape's RBAC requires cluster context; documented).
  • [ ] Process the JSON (findings + per-scanner summary + severity rollup) downstream.

8.5 CI telemetry (Prometheus metrics)

Export scan metrics for observability.

quorum scan . --type repo --metrics quorum.prom --log-format json
  • [ ] Collect quorum.prom as a node_exporter/pushgateway textfile.
  • [ ] Use --log-format json for structured ingestion of progress logs.
  • [ ] Under --advice, extra metrics appear (quorum_advice_enriched, quorum_advice_provider, quorum_advice_fix) — including the verify-the-fix rate.

Distribution: :full image (all 12 scanners, linux/amd64, pre-cached non-expiring grype DB) for self-contained CI; :slim (orchestrator only, amd64+arm64) when the scanners are already on PATH. Native binaries via GoReleaser. All images/binaries are signed (cosign) and attested (SLSA + SPDX SBOM).


9. Assumptions

  • Version. Document aligned to v0.8.3 (revision 2026-07-04); flags, exit codes, scanners, and commands reflect cmd/quorum/scan.go, cmd/quorum/root.go, and internal/adapter/ read at writing time (the version is injected at build/release).
  • Product scope. Quorum is CLI/Docker only. There is no web frontend, relational database, HTTP REST API, or user authentication/accounts. Corresponding items in enterprise templates are treated as N/A by architectural decision (a stateless orchestrator that integrates with CI/CD, not a service).
  • The core has no AI; the advisory layer is opt-in. The deterministic core has no AI. An opt-in advisory layer (--advice) can attach curated remediation + OWASP references (deterministic, no model) and, when explicitly enabled, local (--advice-provider=local) or remote (--advice-provider=remote) AI recommendations. It is off by default, presentation-only, and never touches correlationKey/fingerprint/confidence/aggregated severity/the fail-on gate; without --advice the output is byte-identical (see docs/13-ia.md).
  • Runtime security is N/A for now. The stream model (Falco/Tetragon) is out of scope; it appears only as a future proposal on the README.md/DESIGN.md roadmap.
  • Consensus by domain. VULN is shared by grype + trivy; MISCONFIG/IaC by trivy + checkov + kics + terrascan + tfsec + regula (+ conftest, policy-as-code); K8S_POSTURE by kubescape + polaris + kube-score; IMG_HARDENING is dockle-only (no pair for consensus yet). Kubescape's RBAC stays single-engine because it requires cluster context.
  • Policy-as-code is opt-in. conftest has no built-in rules: with no Rego in ./policy (or via QUORUM_CONFTEST_ARGS), it is reported as error — expected behavior.
  • Optional network dependency. Alias resolution via OSV.dev is optional and degrades gracefully; --offline disables it. The scan does not depend on connectivity to complete. Likewise, the advisory layer's AI providers are optional: if the model is unreachable the report ships without AI advice and the scan never fails; remote requires explicit consent (--advice-allow-egress) and is blocked by --offline.
  • Catalogs derived from real output. The crosswalk mappings (AVD/CKV, KICS UUIDs, Kubescape C-####) were derived from real output of the scanners in Terraform/K8s demos under the false split > false merge rule, but should be checked against the official catalogs before production (per the note in README.md and DESIGN.md §8).
  • Supply chain as a trust boundary. Scanner binaries embedded in the :full image are part of the trust boundary; the release hardens this with sha256-pinned bases, checksum-verified scanners, cosign signing, SLSA build-provenance attestation, and an SPDX SBOM. The knowledge pack + crosswalk carry their own SLSA attestation (verify with gh attestation verify knowledge/owasp/corpus.yaml). For production, pin by digest and verify signatures/attestations.
  • Deterministic confidence/correlationKey. Confidence values and correlation keys are functions of the normalized data; scanner-version changes may alter the input and therefore the output.
  • DoS caps. Per-scanner output is limited by QUORUM_MAX_OUTPUT_BYTES (512 MiB) and on-disk target size by QUORUM_MAX_TARGET_BYTES (20 GiB; 0 disables).