Raw capture โ€” raw/visa-vulnerability-agentic-harness.md


url: https://github.com/visa/visa-vulnerability-agentic-harness title: Visa Vulnerability Agentic Harness (VVAH) author: Visa, Inc. date_fetched: 2026-07-18 date_published: 2026


Visa Vulnerability Agentic Harness โ€” Full Analysis

Overview

VVAH (vvaharness) is Visa's open-source harness for autonomous vulnerability discovery, remediation, and validation using frontier AI models. Built on learnings from Project Glasswing (Anthropic's initiative for AI-assisted vulnerability research), it runs as a four-phase, eleven-stage pipeline from code ingest to validated fix. It is a Python package (โ‰ฅ3.10) with multi-model support via vendor-neutral backend abstraction, outputting Markdown + SARIF 2.1.0 reports.

Version: 1.1.0, Apache 2.0 license.

Repository Structure

vvaharness/
  __init__.py, __main__.py, cli.py, models.py, manifest.py, agentdoc.py
  config/           โ€” YAML config loader with ${ENV} expansion, profiles (default/sdk/full)
  orchestrator/     โ€” pipeline driver: entry.py, scan.py, batch.py, checkpoints.py, store.py, cleanup.py, ...
  pipeline/stages/  โ€” s1_preprocess, s1_autoexclude, s2_threatmodel, s3_decompose,
                      s4_deepdive, s5_prefilter, s6_verify, s7_dedup, s8_chain, s11_validate
  backends/         โ€” llm.py (dispatcher), sdk.py (Anthropic SDK), agent_sdk.py (Claude Agent SDK),
                      oai.py (OpenAI-compatible), claude_cli.py (Claude CLI subprocess),
                      localtools.py (sandboxed tool loop)
  remediation_agent/  โ€” Step 10: runner.py, remediate.py, playbook.py, prompts.py, ...
  validation/       โ€” Step 11: Claude Agent SDK adversarial panel
  report/           โ€” enrich.py, cvss.py, cwe.py, redact.py
  injectors/        โ€” cve_feed.py, design_controls.py
  util/             โ€” environment, tokens, metrics, errlog, prompts, json_extract, status
  lang/             โ€” language hints for ~20 languages

Architecture Deep Dive

Pipeline Architecture (11 stages, 4 phases)

The pipeline is a linear stage pipeline with SQLite checkpointing, allowing resume from any stage:

Phase 1 โ€” Discovery & Modeling (S1โ€“S3) - S1: Agentic exploration via Claude CLI with Read/Glob/Grep/Bash tools โ†’ ContextPackage. Includes deterministic file walk, config-deduplication, and call-graph supplementation. - S2: Threat modeling (STRIDE, OWASP, trust boundaries) โ†’ ThreatModel - S3: Decomposition into prioritized chunks (risk/taint/catch-all/specialist) โ†’ TaskManifest

Phase 2 โ€” Deep Dive & Verification (S4โ€“S6) - S4: Per-chunk deep-dive with majority voting (when temperature >0). Each chunk researched N times, findings intersected. - S5: Deterministic pre-filter + optional semantic pre-dedup - S6: Adversarial verification โ€” fresh agentic session for each finding, tasked with PROVING IT WRONG. Emits TRUE_POSITIVE/FALSE_POSITIVE + CVSS 3.1 vector.

Phase 3 โ€” Synthesis & Reporting (S7โ€“S9) - S7: Two-pass dedup: deterministic (same file + vuln_class + line proximity) then semantic (LLM collapse of same-root-cause findings) - S8: Exploit-chain construction + severity ranking โ†’ FinalReport - S9: Markdown โ†’ SARIF 2.1.0 conversion (fully deterministic)

Phase 4 โ€” Remediation & Validation (S10โ€“S11) - S10: Remediation Agent โ€” per-finding fix proposal/application with playbook-per-CWE-language-framework - S11: Agentic adversarial validation panel (security-architect + penetration-tester + optional cross-repo-analyzer)

Key Techniques

1. Deterministic + LLM hybrid for reliability

Every LLM output is gated by deterministic checks. S1 surveys the repo agentically, but the file inventory comes from a deterministic rglob() walk that cannot be fooled. The call graph is agent-emitted, then validated (hallucinated nodes dropped), then supplemented (regex-scans source for known function calls). S5 pre-filter applies deterministic confidence/evidence gates before the expensive adversarial verification.

The philosophy: the LLM proposes, the pipeline verifies. This is most explicit in s6 adversary verification โ€” a fresh agent is told "assume the finding is WRONG until you personally confirm it" and must trace call chains to an external entry point.

2. Multi-backend abstraction with role-level routing

The backend dispatcher (backends/llm.py) routes each pipeline role independently: cli (Claude CLI subprocess), sdk (Anthropic Python SDK), or openai (OpenAI-compatible API). Each role can use a different backend and model. The default profile uses via: cli for everything (reusing Claude Code login), while sdk.yaml routes everything through the Anthropic SDK with temperature-based majority voting enabled.

The config model:

models:
  preprocess: {id: "claude-sonnet-4-6", via: cli}
  deepdive:   {id: "claude-opus-4-6", via: sdk, temperature: 1.0}
  verify:     {id: "claude-sonnet-4-6", via: cli}
  remediate:  {id: "claude-opus-4-6", via: cli}

3. Temperature-gated majority voting

S4 deep-dive runs each chunk N times and intersects findings. But _effective_runs() checks whether the model actually supports temperature โ€” if _supports_temperature() returns False (Opus 4.7+/Sonnet 4.5+ reject explicit temperature), N collapses to 1 even if config says 3 runs. This prevents paying Nร— cost for identical output. The designer must choose a temperature-capable model AND set temperature: 1.0 to get real diversity-based voting.

4. Config dedup via shape hashing

S1's config-deduplication is a clever optimization for repos with many near-identical per-environment configs (e.g., 5000 service///config.yml variants). It: - Hashes each config's key structure (not values) using format-specific parsers (YAML indent scan, JSON parse, INI sections) - Clusters files by shape hash - Keeps one representative per top-level dir, plus any variant whose body contains a secret or insecure-value pattern NOT present in the representative - Uses a secret regex safety net (API keys, tokens, private keys, JWT patterns, Slack tokens, GitHub tokens) and insecure-value detection (TLS verification disabled, debug mode, anonymous auth)

5. File-qualified call graph supplement

The agent-emitted call graph is bare function names. S1 supplements it by: - Scanning every in-scope source file for function definitions (8 regex patterns across ~6 languages) - Building a def-site index (function โ†’ set of files with line numbers) - For each caller-callee edge: qualifies bare names with file paths, resolving ambiguous callees by longest-common-directory-prefix - Iterating regex-based call discovery for N rounds to expand the graph - Output is qualified edges: src/api/Controller.java::handleRequest โ†’ src/auth/AuthFilter.java::validateToken

This turns a sparse, unvalidated LLM graph into a dense, file-qualified, source-verified graph with ~3-5x more edges than the agent produced alone.

6. Crash-proof LLM output coercion

Every field that takes strict Literal/Enum/int types from LLM JSON carries field_validator(mode="before") that maps common synonyms to valid members and falls back to a safe default. Off-schema values (e.g., kind="rpc", size="tiny", confidence="high") used to kill the entire run. Now they degrade gracefully. The coercion maps are extensive: _EP_KIND_ALIAS maps 30+ strings to 6 entry-point kinds; _ACTOR_ALIAS maps 30+ roles to 7 threat actors; confidence values accept 0-100%, 1-10 scale, NaN, and clamp to [0,1].

Design Decisions & Trade-offs

1. Default edits source code (fix mode)

The shipped default profile runs all 11 stages including S10 remediation in fix mode โ€” meaning vvaharness scan EDITS source files in the target repo by default. This is an unusual choice for a security tool. The README carries prominent warnings, and --stop-after s9 provides a detection-only path. The rationale: the primary metric is Mean Time to Adapt (MTTA), and the bottleneck is triage speed, not discovery. By integrating fix generation into the pipeline, findings go from discovery to validated fix in one run.

2. Claude CLI as default backend (not SDK)

Despite shipping a full Anthropic SDK backend, the default profile uses the Claude CLI subprocess (via: cli). This means no API key is required โ€” just a Claude Code login. The trade-off: no temperature control (so majority voting is disabled by default), and reliance on an external binary. The upside: simpler onboarding, works behind corporate gateways that already support Claude Code.

3. Checkpoint state outside the scanned repo

Checkpoints live in $VVAHARNESS_STATE_DIR/vvaharness.db (SQLite), deliberately outside the scanned repo. The rationale is defense-in-depth: a hostile target could pre-plant checkpoint state that --resume would load. Payloads are JSON (never pickle), so planted bytes can't execute code โ€” but they could poison the pipeline, so state stays outside.

4. Symlink containment is unconditional

S1's file walk drops symlinks whose target resolves outside the repo unconditionally โ€” even when follow_symlinks is explicitly set. The rationale: a committed symlink to ~/.ssh/id_rsa or /etc/passwd would otherwise pull host file content into the LLM prompt. No config flag can re-open this guard.

5. Config from inside the target is refused

By default, VVAH refuses to load config.yaml if it resolves inside the scan target directory (canonical "cd into the checkout, then scan" pattern). This prevents an attacker-influenced checkout from controlling pipeline behavior. The operator must set VVAHARNESS_ALLOW_CWD_CONFIG=1 to override.

6. Validation is Anthropic-only

S11 validation uses the Claude Agent SDK exclusively โ€” via: openai validate roles are refused with exit code 2. Similarly, remediation fix mode (which needs Edit/Write tools) is effectively Anthropic-only since the OpenAI backend is sandboxed to Read/Glob/Grep. This is a practical constraint, not an architectural one โ€” the Claude Agent SDK's permission sandbox (deny-by-default, no Bash, explicit tool grants) aligns with the validation use case.

7. Single-pass by default (no majority voting)

The shipped default uses via: cli with no temperature control, so S4 runs each chunk once. Majority voting requires an SDK backend + temperature-capable model. The trade-off: single-pass is ~3x cheaper per chunk, and s5+s6 provide the false-positive defense instead.

Innovation Points

Comparison with Related Work

Relative to other agentic coding tools (like those documented in the wiki's Agent Design section), VVAH is distinctive in several ways: