13. AI (Artificial Intelligence)¶
Reference version: v0.8.3 — revision of 2026-07-04.
This document describes, faithfully to the code (as-is), the use of Artificial
Intelligence in Quorum (quorum-sec-scan, v0.8.3). The one-sentence summary:
Quorum's core does not use AI and is 100% deterministic; there is an
opt-in advisory layer (--advice, off by default) that can query a
local or remote model, and which never touches the core.
Core (always, no AI). There is no LLM/ML in the path that decides findings:
the orchestration of the 12 OSS scanners, the canonical normalization, the
correlationKey correlation, the crosswalk (crosswalk/*.yaml) and the
consensus score are deterministic and rule-based. The
Fingerprint = sha256(correlationKey) and the pass/fail gate decision are
reproducible and independent of any model. The only external dependency that
could be mistaken for "intelligence" is OSV.dev, a deterministic, non-ML
HTTP API (see §2).
Deterministic OWASP retrieval (Phase 2, under --advice, no AI). Under
--advice, in addition to the Phase 0 templates, Quorum runs RAG over a
versioned, digest-pinned OWASP corpus (knowledge/owasp/corpus.yaml,
package internal/rag) and attaches the most relevant passages as references.
The default retrieval is lexical (deterministic, air-gapped, no model);
there is a semantic path via embeddings when the corpus carries vectors
(built with quorum advise-index) and a local endpoint is available — scan
auto-picks semantic once the corpus is embedded. This is not LLM inference —
it is retrieval over an immutable artifact.
Opt-in advisory layer with an LLM (Phase 1/3, off by default). When — and
only when — the operator passes --advice --advice-provider=local, Quorum
queries a local model (OpenAI-compatible endpoint, e.g. Ollama) to generate a
natural-language recommendation and, under --fix=suggest, a verified
patch (only shown if it survives a re-scan — verify-the-fix). This output is
presentation-only, always labeled "AI-generated, advisory only", and
does not change correlationKey/fingerprint/confidence/severity nor the
gate. Without the flag, the report is byte-identical to a build with no AI.
A remote provider (--advice-provider=remote) also exists and is gated far
more tightly (see §4). The full design and guardrails are in
21-proposta-ia; the risk implications (the OWASP LLM Top 10
stops being N/A once the layer is enabled) are in §4.
Cross-links: DESIGN.md (data model, correlation matrix §6, consensus math, aliasing §7), README.md.
1. Verdict: why the core is AI-free (and AI stays opt-in)¶
Quorum is a correlation + consensus layer over open-source security
scanners. In v0.8.3 there are 12 orchestrated scanners: Trivy, Grype,
Checkov, KICS, Dockle, Kubescape, Polaris, kube-score (K8S_POSTURE), Terrascan,
tfsec, Regula (MISCONFIG/IaC) and Conftest (policy-as-code, runs the Rego from
./policy). All adapters live in internal/adapter. It is CLI/Docker only,
designed to run inside a CI/CD pipeline and to "gate" a build via exit code. In
this design, determinism and reproducibility are first-order requirements: the
same input must produce the same Fingerprint = sha256(correlationKey) on any
run, so that GitHub code scanning / DefectDojo can deduplicate findings across
runs.
Consensus, which in v0.2.3 was restricted to SCA, now also operates on
MISCONFIG/K8S via a crosswalk derived from real scanner output (principle
"false split > false merge") — crosswalk/aws.yaml, crosswalk/azure.yaml,
crosswalk/gcp.yaml (AVD hub) and crosswalk/k8s.yaml (Kubescape C-####
hub). This remains deterministic rule matching, not model inference.
Generative AI is, by nature, probabilistic and non-deterministic, which would directly collide with:
- the "false split > false merge" design principle (when in doubt, keep findings separate — a wrong merge hides risk);
- the requirement of stable fingerprints across runs;
- the auditability required of a security tool that decides whether a build passes or fails.
Because of this, the core carries no model, and the AI parts are strictly opt-in and off by default.
Evidence in the code (verified in v0.8.3):
go.moddeclares onlygithub.com/spf13/cobraandgopkg.in/yaml.v3as direct dependencies (plus indirectpflag/mousetrap). No ML/LLM/vector library is vendored — the opt-in advisory layer talks to an external OpenAI-compatible endpoint overnet/httpand needs no model runtime in the binary.- The deterministic core path (orchestrate → normalize → alias → crosswalk →
correlate → score → report) imports no AI code. Every AI-touching term
(
llm,embedding,rag,advice,advisor,openai) is confined to the opt-in packagesinternal/advisor,internal/rag,internal/enrich,internal/evalsand test fixtures. The word "vector" ininternal/adapter/testdata/sca_grype_alpine.jsonandsca_trivy_alpine.jsonis a CVSS vector string (e.g.CVSS:3.1/AV:N/AC:L/...), unrelated to AI. - Without
--advice, none of the advisory code runs and the report is byte-identical to a build with no AI at all. The core's only network client remainsinternal/alias/osv.go— anet/httpGET againsthttps://api.osv.dev/v1/vulns/<id>(see §2).
flowchart LR
T[target] --> O[orchestrator<br/>parallel fan-out]
O --> S["12 OSS scanners<br/>(trivy/grype/checkov/kics/<br/>dockle/kubescape/polaris/<br/>kube-score/terrascan/tfsec/<br/>regula/conftest)"]
S --> N[normalize<br/>model.Finding]
N --> A["resolve aliases<br/>(OSV.dev — HTTP API)"]
A --> X["crosswalk<br/>rule→canonicalControl<br/>(deterministic YAML)"]
X --> C["correlate<br/>deterministic correlationKey"]
C --> SC["score<br/>confidence (formula)"]
SC --> R[report<br/>SARIF/JSON/XML + metrics]
classDef ai fill:#fdd,stroke:#c00;
classDef det fill:#dfd,stroke:#080;
class O,S,N,X,C,SC,R det;
class A det;
Note: the "resolve aliases" step uses the network (OSV.dev), but remains deterministic and non-ML. No box in the pipeline contains a model. The crosswalk is just rule matching loaded from versioned YAML. The opt-in advisory layer (
--advice) is a separate, post-correlation presentation pass — it is not on this decision path.
2. The only external "intelligence": OSV.dev (deterministic, non-ML)¶
Alias resolution (internal/alias/) unifies vulnerability identifiers — for
example, Grype's GHSA-… and Trivy's CVE-… for the same bug — so they
correlate instead of splitting (DESIGN §7).
This is not AI. It is a three-layer lookup chain, with a deterministic preference for CVE:
flowchart TD
ID[vuln id + scanner-local aliases] --> L1{CVE already present?}
L1 -- yes --> OUT[return CVE]
L1 -- no --> L2{local cache hit?<br/>~/.cache/quorum/aliases.json}
L2 -- yes --> OUT2[return cached value]
L2 -- no --> L3{--offline?}
L3 -- yes --> DEG[degrade: best local id]
L3 -- no --> OSV["OSV.dev GET /v1/vulns/<id><br/>HTTP 8s timeout, 2 retries"]
OSV -- ok --> PICK[preferCVE aliases → write cache]
OSV -- network error --> DEG2[degrade gracefully]
Relevant properties (from internal/alias/resolver.go and osv.go, confirmed
in v0.8.3):
| Property | Value | Why it matters |
|---|---|---|
| Service type | JSON HTTP API (api.osv.dev/v1/vulns/<id>) |
Alias-database lookup, not model inference |
| Determinism | preferCVE: CVE > GHSA > first non-empty |
Same input → same output |
| ML involved | None | Curated community-database lookup |
| Network failure | Graceful degradation (never fails the scan) | DESIGN §7 |
| Turn off | --offline flag (passes osv=nil) |
Fully local/air-gapped run |
| Timeout/retries | Timeout: 8s, MaxRetries=2, exponential backoff |
CI robustness |
| On-disk cache | aliases.json with perm 0600 and schemaVersion |
Reproducibility and hygiene |
Conclusion: OSV.dev is equivalent to a DNS/whois for vulnerabilities — deterministic reference data, not a model that "reasons".
3. AI-template items — status item by item¶
The table below covers each item expected in an enterprise AI section and states
its status for Quorum as-is (v0.8.3). Because the advisory layer is opt-in
and off by default, each item has two states: the default build (no
--advice), and the build with --advice enabled.
| Template item | Default (no --advice) |
With --advice enabled |
|---|---|---|
| Language models (LLM) | N/A — no LLM in the decision path | Opt-in local/remote model, presentation-only (internal/advisor) |
| Model provider (OpenAI/Anthropic/etc.) | N/A — no provider client active | Any OpenAI-compatible endpoint (local, e.g. Ollama) or a remote API |
| Prompts / prompt templates | N/A — no prompts | Fixed system prompt; finding content passed as delimited UNTRUSTED DATA (internal/advisor/prompt.go) |
| RAG (Retrieval-Augmented Generation) | N/A — no generation | RAG-as-artifact over a digest-pinned OWASP corpus (internal/rag), deterministic |
| Embeddings / semantic search | N/A — correlation is by deterministic correlationKey + YAML crosswalk |
Optional: cosine top-k over baked-in corpus vectors when embedded via quorum advise-index |
| Vector database (pgvector/Pinecone/etc.) | N/A — no vector DB | Still none: vectors live inline in the pinned corpus file, not a live DB |
| Fine-tuning / model training | N/A — no model to train | N/A — Quorum trains nothing; it only queries an external model |
| Inference / model serving | N/A — no inference runtime (no ONNX/TF/PyTorch) | Served outside the binary by the operator's endpoint; no runtime is vendored |
| MCP (Model Context Protocol) | N/A — not an MCP client/server | N/A — the advisory layer speaks OpenAI-compatible HTTP, not MCP |
| Agents / agentic orchestration | N/A — "orchestrator" = goroutine fan-out to 12 scanners | N/A — single request/response per finding; the only loop is verify-the-fix (a re-scan, not an agent) |
| Function-calling / model tool-use | N/A — no model to invoke tools | N/A — plain text completion; no tool-calling is used |
| Model guardrails / content moderation | N/A — no model output | Anti prompt-injection prompt, advisory-only labeling, --advice-max cap, output clamped |
| Model evaluation (evals) | Adapter contract tests validate quality (CI coverage) | internal/evals harness measures remediation coverage, OWASP reference relevance, and the verify-the-fix rate (runs in CI, no heavy model) |
| AI observability (token/cost tracing) | N/A — no model calls; telemetry (--metrics, --log-format) is about execution |
Advisory metrics: quorum_advice_enriched{kind}, quorum_advice_provider{provider}, quorum_advice_fix{stage} (verified/proposed = the verify-the-fix rate) |
| Inference costs | N/A — OSV.dev is free and deterministic | Local: on-host compute only. Remote: whatever the external API charges (operator's account) |
| Model versioning / model registry | N/A — versioning is of the binary/image (GoReleaser/GHCR, SLSA attestation + SBOM) | Provider/model recorded on each Advice; the OWASP corpus is digest-pinned and gets its own SLSA provenance attestation each release |
| Privacy of data sent to models | N/A — nothing sent to an LLM; only the vuln id goes to OSV.dev | Local: nothing leaves the host. Remote: only the normalized finding is sent, never source code, and only with explicit consent (see §4) |
4. AI risks — applicability with justification¶
With the advisory layer off (default), there is no AI component in the
execution path and the AI-specific attack surface does not exist — the table
below applies in full. When the operator enables --advice-provider=local,
the OWASP LLM Top 10 items start to apply and are mitigated like this: finding
content is sent as delimited untrusted data (the system prompt forbids
treating it as instructions — anti prompt-injection); output is
advisory-only and labeled, never changing the gate (bounds insecure output
handling/excessive agency); the model is local (no code leaves the host);
and every patch goes through verify-the-fix (a re-scan) before it appears
(mitigates hallucination). The model artifact is a supply-chain dependency
to pin/attest. See 21-proposta-ia §8.
Remote provider (Phase 3,
--advice-provider=remote). Only here does data leave the host: the normalized findings (titles, paths, controls) go to an external API. That is why it is off by default and gated on explicit consent (--advice-allow-egress+QUORUM_ADVICE_API_KEY), blocked by--offline, and refuses--fix(it would upload source code). Only the normalized finding is sent — never the source. Sensitive information disclosure is thus limited to finding metadata, with consent.
| AI risk (OWASP LLM Top 10 / similar) | Default status | Why (and how it is bounded when enabled) |
|---|---|---|
| Prompt injection (direct/indirect) | N/A off | Under --advice: finding content is delimited untrusted data; the system prompt forbids treating it as instructions |
| Jailbreak / system-prompt bypass | N/A off | Under --advice: output is advisory-only and cannot change correlation/gate, so a bypass yields at most bad prose |
| Data poisoning (training-data) | N/A | Quorum trains nothing; the OWASP corpus is digest-pinned and attested |
| Model poisoning / model supply chain | N/A off | Under --advice: the model artifact is an external, operator-pinned dependency; no model ships in the image/binary |
| Hallucination | N/A off | Under --advice: recommendations are advisory-only; every suggested patch must pass a verify-the-fix re-scan before it is shown |
| Insecure output handling | N/A off | Reports (SARIF/JSON/XML) are structured serialization; AI text is a labeled, clamped attachment that never drives the gate |
| Sensitive information disclosure via model | N/A off | Local: nothing leaves the host. Remote: only normalized finding metadata, gated on consent; secrets are redacted in outputs |
| Excessive agency | N/A off | Under --advice: no agent; the only action is proposing a patch, which is never auto-applied (verify-the-fix on a temp copy) |
| Model denial of service / runaway cost | N/A off | Under --advice: --advice-max caps findings; local compute is on-host; remote is off by default. Execution DoS caps: QUORUM_MAX_OUTPUT_BYTES (512MiB), QUORUM_MAX_TARGET_BYTES (20GiB) |
Quorum's real risks (supply chain of the scanner images/binaries, MISCONFIG over-merge, false negatives from a malformed mount) are handled outside this section — see
DESIGN §12(supply chain), §12-security and the README ("Known limitations", "Security of the chain itself"). These are traditional-software risks, not AI risks.
5. Conformance checklist (current state — v0.8.3)¶
- [x] Confirmed the core imports no LLM/AI provider (
go.modreviewed: onlycobra+yaml.v3; the advisory layer talks to an external endpoint overnet/http). - [x] Confirmed the core decision path has no RAG/embeddings/vector DB; the RAG under
--adviceis deterministic retrieval over a digest-pinned artifact (internal/rag). - [x] Confirmed there is no MCP/agent/function-calling anywhere.
- [x] Confirmed there is no inference runtime vendored (no ONNX/TF/PyTorch); a local model is served by the operator's own endpoint.
- [x] Confirmed the 12 adapters (
internal/adapter) and the crosswalk (crosswalk/*.yaml) are deterministic rules, with no ML. - [x] Confirmed the core's only network client is OSV.dev (
internal/alias/osv.go). - [x] Confirmed OSV.dev is switchable off via
--offline(air-gapped mode), which also blocks the remote advice provider. - [x] Confirmed the advisory layer is opt-in and off by default; without
--advicethe report is byte-identical to an AI-free build. - [x] Confirmed no user source code leaves the host: local advice stays on-host; remote sends only normalized findings, is consent-gated (
--advice-allow-egress), and refuses--fix. - [x] Confirmed evals (
internal/evals) gate advisory quality in CI (remediation coverage, OWASP reference relevance, verify-the-fix rate).
6. The advisory layer (implemented — clearly separated from the core)¶
Everything in this section is presentation-only and off by default. It never touches the deterministic core (correlation, fingerprint, confidence, aggregated severity, or the fail-on gate). Without
--advice, none of it runs.📄 The detailed design lives in 21-proposta-ia.md — the opt-in advisory layer (local-first recommendations, two-tier remediation with verify-the-fix, and RAG-as-artifact over a pinned OWASP corpus). Phases 0–3 are now implemented.
The four phases, all shipped in v0.8.3:
- Phase 0 — deterministic enrichment (no model). Curated remediation
templates + OWASP references, matched by
canonicalControl/ruleId/category/type(packageinternal/enrich; data inknowledge/*.yaml). PopulatesMergedFinding.RemediationandReferences. - Phase 2 — RAG-as-artifact (deterministic). Retrieval from a versioned,
digest-pinned OWASP corpus (
knowledge/owasp/corpus.yaml,internal/rag). Lexical by default; semantic when the corpus is embedded viaquorum advise-index. Never generates text — it only retrieves. - Phase 1 — opt-in local LLM.
--advice-provider=localqueries an on-host OpenAI-compatible endpoint for a recommendation;--fix=suggestproposes a patch that must pass a verify-the-fix re-scan (applied to a temp copy, re-scanned with the same scanner, kept only if the finding is gone and the file still parses; never auto-applied). Reproducible viatemperature=0+ an on-disk cache keyed byfingerprint+provider+model. - Phase 3 — opt-in remote provider.
--advice-provider=remotecalls an external API (auth viaQUORUM_ADVICE_API_KEY); gated on--advice-allow-egress, blocked by--offline, and refuses--fix. Only the normalized finding is sent.
Guardrails (enforced in code):
| Guardrail | Rule |
|---|---|
| Explicit opt-in | The whole layer is behind --advice, off by default |
| Untouchable core | The LLM cannot change correlation, fingerprint, confidence or exit code |
| Gate determinism | The pass/fail decision stays 100% deterministic |
| Privacy | Local sends nothing off-host; remote sends only normalized findings, never raw source, and only with consent |
| Offline mode | --offline disables the remote provider (as it already does OSV) |
| Anti prompt-injection | Finding content is treated as delimited data, not instructions |
| Labeling | Every model-generated attachment is marked "AI-generated, advisory only" |
| Auditability | Provider/model recorded on each attachment; temperature=0 + cache for reproducibility |
| Cost/limits | --advice-max cap, timeouts and graceful fallback (same posture as the OSV client) |
| Evals | The internal/evals suite gates advisory quality in CI before release |
Assumptions¶
- The analysis reflects the repository state at v0.8.3, branch
main, verified viago.modand textual search for AI terms across the code. - "OSV.dev" is treated as a deterministic data service (alias lookup), not an ML
system — consistent with
internal/alias/osv.goandDESIGN §7. - The term "orchestrator" in Quorum refers to the parallel fan-out of the 12
scanners (
internal/orchestrator), not an AI agent; this is assumed from the total absence of a model in the decision path. - The crosswalk (
crosswalk/*.yaml) is assumed to be deterministic rule configuration derived from real scanner output, not a learned classifier — consistent with the adapters ininternal/adapter. - The advisory layer is assumed to be presentation-only and off by default;
every claim of "byte-identical without
--advice" is assumed to hold because the advisory packages are only invoked when the flag is set. - Test fixtures (
internal/adapter/testdata/) are assumed not to be part of the production execution path (they are contract-test data); the word "vector" that appears in them refers to CVSS vector strings, not embeddings.