/validate - Exploitability Validation Pipeline
Validates that vulnerability findings are real, reachable, and exploitable before investing in exploit development.
Execution Model
You (Claude) ARE the LLM for this pipeline. Don't just run Python and expect results - you must perform the analysis work.
Step-by-Step Execution
All stages are mandatory. Execute in sequence: 0 → A → B → C → D → E
Stage 0 (Python): Run
build_checklist()to get inventoryfrom packages.exploitability_validation import build_checklist checklist = build_checklist(target_path, output_dir)Output:
{output_dir}/checklist.json(saved automatically)Stage A (Claude): One-shot analysis - identify potential vulnerabilities
- Read source files with the Read tool
- Look for: injection, overflow, UAF, format string, deserialization, etc.
- For each finding, note: file, line, function, vuln_type, proof (actual code)
- Output:
findings.jsonwith status "pending" or "not_disproven"
Stage B (Claude): Process - systematic analysis with attack trees
- Build attack surface: sources, sinks, trust boundaries →
attack-surface.json - Build attack tree: knowledge graph of attack paths →
attack-tree.json - Form hypotheses: testable predictions for each finding →
hypotheses.json - Test hypotheses: gather evidence, verify predictions
- Track failures: why approaches didn't work →
disproven.json - Track proximity: how close to exploitation (0-10 scale) →
attack-paths.json
Stage B produces 5 working documents that MUST be created:
attack-surface.json - Sources, sinks, trust boundaries attack-tree.json - Attack knowledge graph hypotheses.json - Testable predictions (status: testing/confirmed/disproven) disproven.json - Failed approaches and why attack-paths.json - Paths tried, PROXIMITY scores, blockers- Build attack surface: sources, sinks, trust boundaries →
Stage C (Claude): Sanity check - verify against actual code
- Confirm file exists at stated path
- Confirm vulnerable code exists at stated line (VERBATIM)
- Confirm source→sink flow is real
- Confirm code is reachable (called from main/handler)
- Output: Update
findings.jsonwithsanity_checkfield
Stage D (Claude): Ruling - make final determinations
- Rule out test code, dead code, already-mitigated code
- Check for preconditions that prevent exploitation
- Apply hypothesis results from Stage B
- Final status: Exploitable, Confirmed, or Ruled Out
- Output: Update
findings.jsonwithrulingandfinal_statusfields
Stage E (Python): Feasibility - for memory corruption only
from packages.exploit_feasibility import analyze_binary result = analyze_binary(binary_path, vuln_type='buffer_overflow')Output:
exploit-context.json(if binary provided)
Write Results Back
After your analysis, save findings for Stage E:
from packages.exploitability_validation.schemas import create_finding, create_empty_findings
import json
findings = create_empty_findings("D", target_path)
findings["findings"] = [
create_finding("FIND-0001", "/path/file.c", "func_name", 42, "buffer_overflow", "confirmed"),
# ... more findings
]
with open(f"{workdir}/findings.json", "w") as f:
json.dump(findings, f, indent=2)
Agentic vs Non-Agentic Mode
| Mode | Context | How Validation Works |
|---|---|---|
| Non-Agentic | /validate in Claude Code |
Claude (you) performs Stages A-D directly by reading code |
| Agentic | python3 raptor.py agentic |
Semgrep/CodeQL scan first → SARIF converted → deduplication or LLM API validation |
Non-Agentic Mode (Claude Code)
When user runs /validate <path>:
- You are the LLM - perform the analysis yourself
- Run Stage 0 via Python (inventory) →
checklist.json - Stage A: Read files, identify vulnerabilities →
findings.json - Stage B: Build attack trees, form & test hypotheses → 5 working docs
- Stage C: Verify findings against actual code
- Stage D: Make rulings based on Stage B evidence
- Run Stage E via Python if binary provided
User: /validate /tmp/vuln
↓
Claude: Stage 0 → Stage A → Stage B → Stage C → Stage D → Stage E
↓
Output: checklist.json, findings.json, attack-surface.json,
attack-tree.json, hypotheses.json, disproven.json,
attack-paths.json, validation-report.md
Agentic Mode (Python Orchestration)
When user runs python3 raptor.py agentic --repo <path>:
- Semgrep/CodeQL scan first - produces SARIF files
- SARIF conversion - deduplicates findings
- If LLM API available - runs full validation pipeline via API calls
- If no LLM API - deduplication only, skips validation theater
- Stage E - runs if binary provided
python3 raptor.py agentic --repo /tmp/vuln
↓
Semgrep → SARIF (21 findings) → Dedupe (15 unique) → [LLM validation if API key] → Stage E
Key Difference
| Aspect | Non-Agentic | Agentic |
|---|---|---|
| Scanner | None (Claude analyzes directly) | Semgrep + CodeQL |
| LLM | Claude (always available) | External API (optional) |
| Findings source | Claude's analysis | SARIF from scanners |
| Without LLM API | Always works | Deduplication only |
Usage
/validate <target_path> [--vuln-type <type>] [--findings <file>] [--binary <path>] [--skip-feasibility]
Arguments
| Argument | Description |
|---|---|
target_path |
Directory or file to analyze |
--vuln-type |
Focus on specific vulnerability type (optional) |
--findings |
Pre-existing findings.json to validate (skips discovery) |
--binary |
Path to compiled binary for Stage E feasibility analysis |
--skip-feasibility |
Skip Stage E even for memory corruption vulns |
Vulnerability Types
command_injection- OS command injectionsql_injection- SQL injectionxss- Cross-site scriptingpath_traversal- Directory traversalssrf- Server-side request forgerydeserialization- Insecure deserializationbuffer_overflow- Buffer overflow (memory corruption)format_string- Format string vulnerabilities
What This Does
Runs a 6-stage validation pipeline:
| Stage | Purpose | Output |
|---|---|---|
| 0: Inventory | Build checklist of all code | checklist.json |
| A: One-Shot | Quick exploitability + PoC attempt | findings.json |
| B: Process | Systematic analysis with attack trees | working docs |
| C: Sanity | Verify against actual code (catch hallucinations) | validated findings |
| D: Ruling | Filter test code, preconditions, hedging | confirmed findings |
| E: Feasibility | Binary constraint analysis (memory corruption only) | final findings |
Note: Stage E only runs for memory corruption vulnerabilities (buffer_overflow, format_string, use_after_free, etc.). Web vulnerabilities skip directly to final output after Stage D.
Examples
# Scan a web application for command injection
/validate ./webapp --vuln-type command_injection
# Validate all vulnerability types in a codebase
/validate ./src
# Validate pre-existing scanner findings
/validate ./src --findings scanner-results.json
# Validate memory corruption with binary path for Stage E
/validate ./vuln_app --vuln-type format_string --binary ./build/vuln
# Skip feasibility analysis even for memory corruption
/validate ./vuln_app --vuln-type buffer_overflow --skip-feasibility
Output
Results saved to .out/exploitability-validation-<timestamp>/:
.out/exploitability-validation-20260122-143022/
├── checklist.json # All functions to check
├── findings.json # Final validated findings
├── attack-tree.json # Attack knowledge graph
├── hypotheses.json # Tested hypotheses
├── disproven.json # Failed approaches
├── attack-paths.json # Paths tried + PROXIMITY
├── attack-surface.json # Sources, sinks, boundaries
├── exploit-context.json # Binary context (Stage E, if applicable)
└── validation-report.md # Human-readable summary
Stage E: Exploit Feasibility Integration
For memory corruption findings, Stage E automatically runs binary constraint analysis:
from packages.exploit_feasibility import analyze_binary, save_exploit_context
# Analyzes: PIE, NX, Canary, RELRO, glibc mitigations, ROP gadgets, bad bytes
# Returns: verdict (Likely/Difficult/Unlikely) + chain breaks + recommendations
result = analyze_binary(binary_path, vuln_type='format_string')
context_file = save_exploit_context(binary_path) # Survives context compaction
Final Status After Stage E:
| Verdict | Final Status | Meaning |
|---|---|---|
| Likely | Exploitable | Clear path to code execution |
| Difficult | Confirmed (Constrained) | Primitives exist but hard to chain |
| Unlikely | Confirmed (Blocked) | No viable path with current mitigations |
| N/A | Confirmed | Web/injection vuln (Stage E skipped) |
Stage B: Systematic Analysis
Stage B is where superficial scanning becomes thorough validation:
| Without Stage B | With Stage B |
|---|---|
| Quick ruling based on gut feel | Evidence-backed ruling from tested hypotheses |
| "Looks like a false positive" | "Hypothesis H2 disproven: ws:// only in comment (evidence: line 463)" |
| No record of what was tried | disproven.json documents failed approaches |
| No proximity tracking | PROXIMITY scores show how close to exploitation |
If you're tempted to skip Stage B because findings "obviously" look like false positives:
- Create the hypothesis anyway (e.g., "H1: SSRF via urlretrieve")
- List testable predictions (e.g., "P1.1: Script runs at runtime")
- Gather evidence to disprove (e.g., "Script outputs .h file → build-time only")
- Record in
disproven.jsonwith lesson learned
This creates an audit trail and catches cases where "obvious" false positives are actually exploitable.
MUST-GATEs
This command enforces strict validation gates:
- ASSUME-EXPLOIT: Investigate as if exploitable until proven otherwise
- STRICT-SEQUENCE: Follow methodology, additional ideas presented separately
- CHECKLIST: Track coverage compliance
- NO-HEDGING: Verify all "if/maybe/uncertain" claims
- FULL-COVERAGE: Check ALL code, no sampling
- PROOF: Show vulnerable code for every finding
When to Use
- After
/scanor/agenticproduces findings - Before investing time in
/exploitdevelopment - When you suspect false positives from scanners
- To validate third-party security reports
Workflow Integration
/scan -> /validate -> /exploit
| | |
v v v
Finds Confirms Develops
vulns they're working
real exploits