Audit Stage
The audit stage inspects planned components for security vulnerabilities and
emits raw findings. It has two concrete strategy implementations. The
orchestrator selects one from ScanExecution.audit_strategy.
Location
src/stages/audit/
Stage class hierarchy
BaseAuditStage (src/stages/audit/stage.py)
├── DefaultAuditStage strategy = "default"
└── VariantAnalysisAuditStage strategy = "variant_analysis"
class BaseAuditStage(BaseStage[StageInput, StageOutput]):
name = StageName.AUDIT
strategy: ClassVar[str]
required_artifacts = ("source_snapshot", "plan_artifact", "threat_model")
produced_artifacts = ("raw_findings", "audit_component_state")
Strategy selection
ScanExecution.audit_strategy |
Concrete class |
|---|---|
"default" / "component" |
DefaultAuditStage |
"variant_analysis" / "variant" |
VariantAnalysisAuditStage |
DefaultAuditStage
Audits planned components in parallel. For each component:
- Builds an audit prompt from:
- The base template (
stages/audit/prompts/default.txt) - Plan component scope (files/paths)
- Threat model artifact context
- Plugin prompt sections (
context.plugins.plugin.build_prompt_sections(...)) - Plugin schema overrides applied to
schemas/findings.json - PR review focus block (if
metadata["pr_review"]is present) - Runs an agent task (
purpose="audit.default") for each component. - Parses structured findings from agent output using the effective schema.
- Emits
finding_updatedfor each parsed finding. - After all components: writes
vega.raw_findingsandvega.audit_component_stateartifacts. - Emits
raw_findings_ready.
Parallelism
Component work runs in a thread pool controlled by
RunPolicy.max_workers_per_runner. The default is 1 (sequential). Set
VEGA_MAX_WORKERS_PER_RUNNER or VEGA_CORE_AUDIT_WORKERS_MAX for parallel
execution.
Audit resume
When execution.audit_resume_artifact is provided with
execution.audit_resume_policy="skip_completed":
- Loads the saved
vega.audit_component_stateartifact. - Components marked as completed in that artifact are skipped.
- Their findings are carried forward into the new
raw_findingsartifact. - Only pending or failed components are re-audited.
This supports partial scan recovery and multi-shard scan orchestration.
Component sharding
execution.assigned_component_ids restricts audit to specific component ids.
execution.audit_shard_id tags the shard for artifact naming. Backend uses
this to split a large repository's audit across multiple runner containers.
VariantAnalysisAuditStage
A specialized strategy for variant analysis — searching for similar patterns of
a known vulnerability class across the codebase. Requires
ScanIntent.variant_context to be set. Uses stages/audit/prompts/variant_analysis.txt
and focuses agent prompts on the known pattern.
Finding schema
The agent produces structured findings validated against
stages/audit/schemas/findings.json. Each finding includes:
{
"finding_id": "unique-id",
"title": "Vulnerability title",
"description": "Detailed description",
"severity": "critical | high | medium | low | info",
"bug_class": "...",
"file_path": "src/service.py",
"line_start": 42,
"line_end": 55,
"component_id": "auth/login_handler",
"evidence": ["relevant code snippet"],
"attacker_profile": "...",
"required_state": "...",
"required_services": "..."
}
Plugins can override enum values for bug_class, attacker_profile,
required_state, and required_services through
StagePlugin.output_schema_overrides(...). See Plugin System
for details.
Domain events
| Event kind | When emitted |
|---|---|
component_worker_started |
Component audit begins |
component_worker_completed |
Component audit finishes |
component_worker_failed |
Component agent call fails |
component_worker_cancelled |
Component cancelled |
component_worker_skipped |
Component skipped (resume) |
finding_updated |
Each parsed finding |
raw_findings_ready |
All components processed |
finding_updated payload
The event carries the full canonical finding object. Key fields:
{
"finding_id": "run123:auth:login_handler:finding-1",
"bug_id": "...",
"title": "src/auth/login.py: Missing authorization check",
"bug_title": "Missing authorization check",
"blame_path": "src/auth/login.py",
"bug_class": "broken_auth",
"category": "broken_auth",
"summary": "...",
"bug_description": "...",
"affected_paths": ["src/auth/login.py"],
"severity": "high",
"likelihood": "high",
"confidence": "high",
"threat_model_similarity": "medium",
"attacker_profile": "...",
"required_state": "...",
"required_services": [],
"status": "candidate",
"root_cause": "...",
"root_cause_sections": {"overview": "...", "analysis": "...", "attack_vector": {...}},
"buggy_locations": [{"file_path": "...", "location_kind": "sink", ...}],
"evidence": ["..."],
"suggested_fix": "...",
"source_stage": "audit",
"source_strategy": "default",
"component_id": "auth:login_handler",
"component_name": "login_handler",
"module_name": "auth",
"metadata": {...}
}
Backend persists findings from this event. The finding_id is stable across
partial scans of the same component.
Deduplication
Raw findings from all scan runners flow into SharedTriageService via
ScanTransition.apply_output(...) after the audit stage completes. See
Findings & Triage.
Artifact outputs
| Artifact kind | Content |
|---|---|
vega.raw_findings |
All raw agent findings across all components |
vega.audit_component_state |
Per-component status (pending/completed/failed) for resume |
Cancellation
BaseAuditStage uses context.checkpoint(StageName.AUDIT, progress) at
component boundaries. When cancellation is requested, in-flight agent calls are
cancelled via context.cancellation.cancel_active_agent_calls(), and a
stage_cancelled event is emitted with the current progress.
Error handling
| Condition | Behavior |
|---|---|
| Single component agent failure | Component marked failed; audit continues |
| All components fail | Stage fails with audit_all_components_failed |
| Agent timeout (per-stage) | StageError(code="audit_timeout", retryable=True) |
| Schema parse failure | Finding skipped; warning emitted |