fallow security produces deterministic candidates. It does not call a model, decide exploitability, or emit verified vulnerabilities. Use this recipe when an agent or external harness should turn raw candidates into a shorter survivor list.
Use the CLI when you want a standalone JSON file:
fallow security --format json --surface --quiet > fallow-security.json
Use MCP when an agent is already in an edit loop:
{
"root": "/path/to/repo",
"surface": true,
"paths": ["src/routes/login.ts"]
}
surface: true forwards --surface and includes top-level attack_surface[] entries. Set gate to new for changed-line candidates or newly-reachable for candidates that became reachable from entry points; newly-reachable requires changed_since. paths forwards repeated --file filters and scopes returned candidates to matching anchors, trace hops, source-trace hops, and unresolved-callee diagnostics.
Each candidate includes severity, a review-priority tier (high, medium, or low). It is not a verified vulnerability verdict. When reachability.taint_confidence is present, use it to distinguish arg-level source association from weaker module-level reachability.
For each security_findings[] item, build one packet from deterministic fallow evidence plus caller-collected source windows:
{
"schema_version": "fallow-security-verifier-input/v1",
"finding_id": "security:...",
"severity": "high",
"candidate": {
"source_kind": "http-request-input",
"sink": {},
"boundary": {}
},
"trace": [],
"taint_flow": null,
"taint_confidence": "arg-level",
"reachability_trace": [],
"attack_surface": null,
"source_windows": [
{
"path": "src/routes/login.ts",
"start_line": 12,
"end_line": 52,
"text": "..."
}
],
"blind_spots": {
"unresolved_edge_files": 0,
"unresolved_callee_sites": 0,
"unresolved_callee_diagnostics": null
}
}
Collect source windows from disk after the scan. Keep them outside fallow output so the core stays deterministic, compact, and provider-neutral.
blind_spots.unresolved_callee_diagnostics can copy the top-level fallow output when a verifier queue wants sample locations for dynamic-dispatch follow-up. It is bounded metadata, not proof of a vulnerability.
Ask the verifier to dismiss candidates unless the supplied evidence supports a real exploit path:
You are verifying one fallow security candidate.
Fallow is a deterministic candidate producer, not a vulnerability oracle.
Use only the supplied candidate, trace, attack-surface entry, and source windows.
Do not assume data flow beyond the provided code.
Check:
1. Is the input attacker-controlled?
2. Does the value reach the reported sink?
3. Is the reported boundary relevant to exploitability?
4. What concrete impact would remain if the candidate is real?
5. Is there an existing defensive control that dismisses it?
Return only JSON matching fallow-security-verdict/v1.
If attack_surface.defensive_boundary.verification_prompt is present, include it as an additional question, not as a verdict.
Require a compact JSON verdict:
{
"schema_version": "fallow-security-verdict/v1",
"finding_id": "security:...",
"verdict": "survivor",
"reason": "The request query value reaches execSync without validation.",
"impact": "Command injection through the id query parameter.",
"evidence_checked": {
"source": true,
"sink": true,
"boundary": true,
"trace": true,
"source_window": true
},
"dismissal_reason": null,
"fix_direction": "avoid-shell"
}
Allowed verdicts:
survivor: the verifier could not dismiss the candidate from the supplied evidence.dismissed: the candidate is not exploitable from the supplied evidence.needs-human-review: the evidence is incomplete, contradictory, or blocked by missing context.Store verifier output beside the original fallow JSON, keyed by finding_id. Do not write verdict fields back into fallow output.
Join the candidates and the verdict file with fallow security survivors to render only the candidates the verifier retained:
fallow security --format json --quiet > candidates.json
# (verifier writes verdicts.json keyed by finding_id)
fallow security survivors --candidates candidates.json --verdicts verdicts.json
It reports summary.unverdicted so unreviewed candidates stay visible; add --require-verdict-for-each-candidate to fail CI when any candidate lacks a verdict. To see where the structural trace stopped (unresolved callees the verifier should inspect by hand), run fallow security blind-spots.
Candidate quality depends on source and trace fidelity. HTTP-input source patterns are receiver-gated to avoid broad *.query collisions with unrelated APIs, but framework-specific request aliases can still need verifier judgment. reachability.taint_confidence distinguishes arg-level from module-level source association; use severity and taint_confidence for triage order, then verify source control, value flow, sink behavior, and defensive controls from source windows before reporting a survivor.