Skip to main content

Tamper-evident runtime evidence layer for AI agents: conformal risk scoring, hash-chained audit trails, and signed attestation plus execution receipts per MCP tool call

Project description

Vaara

PyPI License CI OpenSSF Scorecard OpenSSF Best Practices Hugging Face Space

Vaara is an open-source runtime evidence layer for AI agents. It sits in front of an agent's tool calls, decides whether each one is allowed, and writes a tamper-evident record of what happened. When you have to prove what an agent actually did, to an auditor, a regulator, or a customer, that record is the proof. Runs in your own environment. No SaaS, no telemetry.

The original driver is EU AI Act compliance, but the same trail answers any "show me exactly what the agent did, and why" question.

  • Gate every agent tool call against your own policy: allow, block, or escalate.
  • Hash-chained, tamper-evident audit trail an outside party can verify without trusting your stack.
  • Article-level EU AI Act evidence report, honest about gaps instead of rubber-stamping them.

How it works

Every tool call an agent makes passes through Vaara before it runs:

  1. Intercept. Vaara catches the call (fs.write_file, tx.transfer, an MCP tools/call, and so on) through your framework's own hook, or transparently as an MCP proxy in front of an upstream server.
  2. Score and decide. Each call gets a risk score and an allow / block / escalate decision against your policy.
  3. Record. The call, the score, the decision, and the real-world outcome are written to a hash-chained audit trail. An outside auditor can verify the chain is intact without trusting your stack or your word.

The scoring blends five expert signals and keeps adapting as outcomes come back, and each risk score carries a confidence interval with a coverage guarantee that holds regardless of the input distribution. Those are the properties an auditor can check independently; the math is in Benchmarks and docs/formal_specification.md.

Install

pip install vaara

Python 3.10+. Zero runtime deps. Optional XGBoost classifier: pip install vaara[ml]. Releases ship with SLSA Build Level 3 provenance, verifiable via slsa-verifier verify-artifact.

Quick start

from vaara.pipeline import InterceptionPipeline

pipeline = InterceptionPipeline()
result = pipeline.intercept(
    agent_id="agent-007",
    tool_name="fs.write_file",
    parameters={"path": "/etc/service.yaml", "content": "..."},
    agent_confidence=0.8,
)
if result.allowed:
    pipeline.report_outcome(result.action_id, outcome_severity=0.0)
else:
    print(result.reason)

report_outcome closes the loop: the signal weights reweight based on which ones predicted the outcome.

What evidence looks like

vaara compliance report --format json against a real audit trail produces an article-level evidence record an auditor can read directly. Articles without recorded events return evidence_insufficient, not a rubber-stamp.

{
  "system_name": "Acme HR Assistant",
  "overall_status": "evidence_insufficient",
  "trail_integrity": {"size": 105, "chain_intact": true},
  "articles": [
    {"article": "Article 12(1)", "title": "Record-Keeping (Logging)",
     "status": "evidence_sufficient", "strength": "strong", "evidence_count": 105},
    {"article": "Article 15(1)", "title": "Accuracy, Robustness and Cybersecurity",
     "status": "evidence_insufficient", "strength": "absent", "evidence_count": 0}
  ]
}

Each verdict carries the threshold-vs-observed snapshot, the rationale, and the underlying audit records, so a reviewer can trace status back to a concrete event without re-running the engine. The same data renders as a styled PDF for Notified Bodies (--format pdf, needs vaara[pdf]), a static HTML dashboard (vaara compliance dashboard), or a Sigstore-signed handoff envelope (vaara trail export, optional ML-DSA-65 / FIPS 204 post-quantum signer via vaara[pq]).

Benchmarks

Held-out test recall 84.7% (95% Wilson [82.4, 86.7]) at a 4.1% false-positive rate, and 1.2% FPR on benign tool calls under live injection pressure. The hot-path rule scorer adds 140 µs mean / 210 µs p99 per call on commodity CPU. Every figure is reproducible end-to-end via make bench.

Full numbers, corpus, calibration, and chain of custody
  • 12,155-entry adversarial corpus (250 hand-curated + 11,905 LLM-generated), 70/15/15 split stratified by (category, source)
  • Classifier v9 (236 hand-features + 384-dim MiniLM embeddings) at calibrated threshold 0.9150 on held-out TEST n=1,827: recall 84.7% [82.4, 86.7] at FPR 4.1% [2.9, 5.7]. Phase 1 PAIR scale-up to n=300 per attacker family lands at 88.1% [85.8, 90.1]
  • Cross-model held-out recall 66.8% [64.9, 68.7] over n=2,277 with no eval-set attacker model in TRAIN; the weakest sub-cell is data_exfil against a closed-weight model at 38.9% [35.3, 42.5]. This is the honest worst case; the in-distribution number above is the easier denominator
  • BIPIA-pressure FPR on benign tool calls 1.2% [0.4, 3.6] across four agent backends (Claude Haiku 4.5, Llama-3.1-8B, Mistral-7B, Qwen-2.5-7B), n=244. Collapses from 35.2% on v8 to 1.2% on v9
  • Multi-attacker PAIR robustness: 0/25 successes per attacker across Qwen2.5-32B, Qwen2.5-72B, Llama-3.3-70B on identical seeds, Wilson upper 13.3%
  • 140 µs mean / 210 µs p99 for the hot-path rule scorer on commodity CPU; the MiniLM classifier is opt-in (vaara[ml]) and not in that path
  • Distribution-free conformal coverage on the score; MWU regret bound O(sqrt(T log N))
  • Chain of custody: corpus, split, training commit, and bundle SHAs locked and printed by every script
  • Current methodology and ship-gate record in vaara-bench-v0.39; per-cell breakdown in vaara-bench-v0.37. Historical bench docs live under bench/

Each figure is reproducible from the public corpus or the bench pipeline in bench/.

Framework adapters

Native adapters in src/vaara/integrations/ route the major Python agent frameworks through Vaara's pipeline. Each intercepts via the framework's own callback or hook surface, scores, gates, and emits the same audit events as a direct pipeline.intercept(). Frameworks are not hard dependencies (lazy import, duck typing), so audit records hash-chain together regardless of which one the action came through.

Framework Entry point Use
LangChain VaaraCallbackHandler, vaara_wrap_tool Slots into config={"callbacks": [...]} or wraps per-tool
CrewAI VaaraCrewGovernance Wraps a crew so every agent action passes through scoring + audit
OpenAI Agents SDK VaaraToolGuardrail, vaara_wrap_function Function-tool wrap, compatible with Responses API and Agents-SDK tracing
MCP server vaara.integrations.mcp_server Exposes scoring, audit, policy reload as MCP tools

For Vaara in front of an upstream MCP server, see MCP proxy below.

Upstream-signal adapters (cloud + OSS guardrails)

Adapters route findings from cloud and OSS guardrails into Vaara's audit trail and OVERT envelope. The filter runs in the deployer's environment; Vaara records the verdict, normalises 68 provider categories onto a shared vocabulary, and tags each finding against the relevant AI Act articles. Each adapter returns a ContentSafetyFinding the deployer routes into pipeline.intercept(context=finding.to_audit_context()). Article-by-article mapping in COMPLIANCE.md.

Seven cloud and OSS guardrails: Bedrock, Azure, GCP, NeMo, Guardrails AI, LLM Guard, Rebuff
Provider Adapter Extra Wraps
AWS Bedrock Guardrails BedrockGuardrailsAdapter vaara[bedrock] ApplyGuardrail across five Bedrock policy buckets
Azure AI Content Safety AzureContentSafetyAdapter vaara[azure-content-safety] analyze_text, Prompt Shields, Protected Material, Groundedness
GCP Model Armor GcpModelArmorAdapter vaara[gcp-model-armor] sanitize_user_prompt, sanitize_model_response
NVIDIA NeMo Guardrails NemoGuardrailsAdapter vaara[nemo-guardrails] GenerationResponse.log.activated_rails (input / dialog / output / retrieval)
Guardrails AI GuardrailsAIAdapter vaara[guardrails-ai] ValidationOutcome.validation_summaries from Guard.parse / Guard.validate
LLM Guard LLMGuardAdapter vaara[llm-guard] scan_prompt / scan_output
Rebuff RebuffAdapter vaara[rebuff] DetectResponse across heuristic, model, vector layers + canary-word leak check

Mapping table at src/vaara/integrations/_content_safety_articles.py. Rationale in COMPLIANCE.md.

HTTP API

The same scorer and audit trail are available over HTTP for non-Python agents and control planes that prefer a network boundary.

pip install 'vaara[server]'
vaara serve --host 0.0.0.0 --port 8000

curl -sX POST http://localhost:8000/v1/score \
  -H 'content-type: application/json' \
  -d '{"tool_name":"tx.transfer","agent_id":"agent-007","base_risk_score":0.5}'

Wire contract in docs/openapi.yaml, recipes under examples/recipes/. Operator endpoints include POST /v1/policy/reload (atomic hot policy swap) and named detectors POST /v1/detect/injection and POST /v1/detect/pii, with matching CLI subcommands that exit non-zero on detection for CI gating.

The first-party TypeScript client ships on npm as @vaara/client: typed wrappers over every v1 endpoint, Node 18+, ESM. JS/TS agents call Vaara without a Python sidecar.

import { VaaraClient } from "@vaara/client";
const vaara = new VaaraClient({ baseUrl: "http://localhost:8000" });
const r = await vaara.score({ tool_name: "tx.transfer", agent_id: "agent-007", base_risk_score: 0.6 });
if (r.decision === "deny") throw new Error("blocked");

MCP proxy

VaaraMCPProxy sits between an MCP client (Claude Code, Cursor, any MCP host) and an upstream MCP server. Every tools/call routes through Vaara's pipeline before reaching the upstream: allowed calls forward transparently and report the outcome back to the scorer, blocked calls return an MCP isError: true with the reason. The handshake and notifications/* forward unchanged.

vaara-mcp-proxy \
  --upstream npx --upstream-arg -y --upstream-arg @sap/mdk-mcp-server \
  --db ./mcp_audit.db

Point your MCP client at the proxy instead of the upstream; the audit chain captures every call without changing client or upstream behavior. Upstreams can be local (--upstream launches a local stdio server) or remote (--upstream-url NAME=URL over Streamable HTTP). This is distinct from mcp_server, which exposes Vaara itself as a tool.

Fleet shape: one proxy, many upstreams, multi-tenant policy

vaara-mcp-proxy also runs over Streamable HTTP with fan-out, so one process can serve a fleet:

vaara-mcp-proxy \
  --transport http --http-host 127.0.0.1 --http-port 8765 \
  --upstream 'github=npx -y @github/mcp-server' \
  --upstream 'sap=npx -y @sap/mdk-mcp-server'

Each POST /mcp reads two headers: X-Vaara-Upstream picks the upstream slot, X-Vaara-Tenant scopes the policy, audit chain, and OVERT envelope. Single-upstream deployments keep the silent-default contract; multi-upstream deployments require X-Vaara-Upstream per call and return 400 with the slot list when it is missing. vaara serve --policy-dir DIR loads one policy per file (filename stem becomes tenant_id, default.yaml is the fallback) and hot-reloads per tenant.

Operator perimeter and request attestation

Repeatable --allow-tool / --deny-tool flags (and the same for resources and prompts) filter the MCP surface. Filtered tools are dropped from tools/list before the client sees them and any matching call is rejected at the perimeter without contacting the upstream. Denylist wins on overlap; no flags means passthrough. Every allowed resources/read and prompts/get writes a request+decision audit pair so a regulator can reconstruct exactly what the agent read.

OVERT envelopes per interaction turn on with --overt-signing-key, --overt-operator-key, --overt-receipts-dir. SEP-2787 request attestation paired with an execution receipt turns on with --attest-signing-key PATH and --attest-receipts-dir DIR: each allowed call writes a pre-execution attestation and a post-execution receipt linked by a backLink digest. Key type auto-detects from the file (EC P-256 = ES256, RSA = RS256, raw bytes = HS256). Generate and verify offline:

vaara keygen --attest --out attest_key.pem
vaara attest verify  0000000001-ab12cd34-attest.json  --pubkey-file attest_key.pem.pub
vaara receipt verify 0000000001-ab12cd34-receipt.json --attestation 0000000001-ab12cd34-attest.json --pubkey-file attest_key.pem.pub

Both verifiers exit non-zero on any failed check, so they drop straight into CI. Format in docs/execution-receipts.md, conformance surface in docs/sep2787-conformance.md.

Worked examples: examples/github-mcp-proxy-demo/ (Vaara in front of github/github-mcp-server, 42 tools) and examples/sap-mcp-proxy-demo/ (community SAP MCP servers).

OVERT 1.0 attestation

OVERT 1.0 is an open standard for runtime trust in AI systems (overt.is, authored by Glacis Technologies, published 25 March 2026): a signed, schema-closed envelope a relying party can verify offline without trusting the emitter. Vaara is the Arbiter in OVERT terms and ships Protocol Profile 1.0 Base Envelopes (canonical CBOR per RFC 8949, Ed25519 signatures, HMAC-SHA256 commitments, closed 9-field schema) alongside every audit record when attestation is enabled.

pip install 'vaara[attestation]'
from vaara.attestation.overt import emit_base_envelope, make_request_commitment, encoder_binary_identity

envelope = emit_base_envelope(
    signing_key=key,
    request_commitment=make_request_commitment(payload, operator_key=op_key),
    encoder_binary_identity=encoder_binary_identity(arbiter_version=f"vaara/{vaara.__version__}", policy_hash=ph),
    non_content_metadata={"action_class": "tx.transfer", "decision": "escalate"},
    monotonic_counter=42,
    arbiter_instance_identifier=uuid_bytes,
)

vaara overt verify RECEIPT.cbor --pubkey-file PUB.bin validates any canonical-CBOR Base Envelope. The verifier reads only the wire format and takes no dependency on Vaara's emitter, so any conformant implementation can route through it. Adjacent surfaces (vaara.attestation.iap notary + transparency log, vaara.attestation.s3p aggregate intervals, an experimental AMD SEV-SNP TEE hook) and the OVERT 1.0 Part 3 control walk are in COMPLIANCE.md.

Where things live

Path Contents
docs/formal_specification.md MWU regret bound, conformal coverage, security properties
docs/conformal-prediction.md Plain-language explainer for compliance reviewers and legal counsel
docs/execution-receipts.md Execution receipts paired with SEP-2787 request attestation
docs/sep2787-conformance.md What vaara attest verify / vaara receipt verify check
docs/COMPLIANCE.md EU AI Act (Art. 9, 11 to 15, 61) and DORA (Art. 10, 12, 13) mapping, eval numbers
docs/VERDICTS.md Per-article evidence sufficiency thresholds and decision tree
CHANGELOG.md Version-by-version feature evolution
docs/PRIOR_ART.md When each Vaara concept first shipped, plus adjacent published work
docs/OWASP_AGENTIC.md Mapping to OWASP Top 10 for Agentic Applications 2026
docs/OVERT_CONTROLS.md Mapping to OVERT 1.0 Part 3 Agentic AI Controls
docs/mit_ai_risk_repository_mapping.md Coverage map against the MIT AI Risk Repository v4
docs/signing-keys.md Release signing and verification
.github/SECURITY.md Security policy and reporting
.github/CONTRIBUTING.md Contribution guidelines

Acknowledgements:

Vaara helps deployers assemble evidence for their own conformity work. It does not certify compliance or constitute legal advice. Deployers own their obligations under the EU AI Act and other applicable law.

License

Apache 2.0. See LICENSE.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vaara-0.47.0.tar.gz (920.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vaara-0.47.0-py3-none-any.whl (788.5 kB view details)

Uploaded Python 3

File details

Details for the file vaara-0.47.0.tar.gz.

File metadata

  • Download URL: vaara-0.47.0.tar.gz
  • Upload date:
  • Size: 920.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for vaara-0.47.0.tar.gz
Algorithm Hash digest
SHA256 ab2123d8a61b7540d5ba6e02f10520c58ac30fe95aae5904dae11a6af4da6c9f
MD5 cf28ef63a9a6530e60a3e33a432bb5d2
BLAKE2b-256 160edb2afe6a13ddb44043af852e8decad8c1637d49a07fc4ca960a69bf9d6be

See more details on using hashes here.

Provenance

The following attestation bundles were made for vaara-0.47.0.tar.gz:

Publisher: release.yml on vaaraio/vaara

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vaara-0.47.0-py3-none-any.whl.

File metadata

  • Download URL: vaara-0.47.0-py3-none-any.whl
  • Upload date:
  • Size: 788.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for vaara-0.47.0-py3-none-any.whl
Algorithm Hash digest
SHA256 488dcb156f6aba1d40177682937b95bf7e356c2b68565e6eac7ecab91fa1ff40
MD5 776365de0833a8d9c140f1e3127b7d8f
BLAKE2b-256 0fb18d4b0527807a8d9e0548b305f9e5e61ba7a1d7a0cd1d48768247345905e4

See more details on using hashes here.

Provenance

The following attestation bundles were made for vaara-0.47.0-py3-none-any.whl:

Publisher: release.yml on vaaraio/vaara

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page