Overview
The exploitability validation pipeline ensures security findings are not false positives by systematically verifying they are real, reachable, and exploitable through a 6-stage process.Why Validation?
Static analysis tools produce many findings, but not all are exploitable:- Hallucinated findings: File doesn’t exist, code doesn’t match scanner output
- Unreachable code: Dead code, test-only functions
- Protected paths: Effective sanitization, impossible preconditions
- Binary constraints: Mitigations that block exploitation
The 6-Stage Pipeline
Stage 0: Inventory
Purpose: Build a complete checklist of all code to be analyzed.Output
checklist.json - Complete function inventory:
Execution
Stage A: One-Shot Analysis
Purpose: Quick exploitability assessment with PoC attempts.Gates Applied
- GATE-1 [ASSUME-EXPLOIT]: Assume findings are exploitable until proven otherwise
- GATE-4 [NO-HEDGING]: No “maybe” or “could be” - verify all claims
- GATE-6 [PROOF]: Provide concrete proof and vulnerable code
Output
findings.json - Initial exploitability assessment:
Status Values
poc_success- PoC successfully demonstrated vulnerabilitynot_disproven- Cannot rule out, needs deeper analysis (Stage B)disproven- Proven safe, no further analysis needed
Stage B: Process
Purpose: Systematic analysis for “not_disproven” findings using attack trees and knowledge graphs.Gates Applied
ALL gates (1-6):- GATE-1: Assume exploitable
- GATE-2: Strictly follow instructions
- GATE-3: Update checklist, collect evidence
- GATE-4: No hedging
- GATE-5: Full code coverage
- GATE-6: Provide proof
Working Documents
Stage B creates 5 specialized documents:1. attack-tree.json
Knowledge graph of attack paths:2. hypotheses.json
Testable predictions:3. disproven.json
Failed approaches:4. attack-paths.json
Attempted exploitation paths with PROXIMITY scoring:10- Working exploit8-9- Very close, minor obstacles6-7- Feasible path, some blockers4-5- Significant obstacles1-3- Far from exploitation0- Not viable
5. attack-surface.json
Sources, sinks, and trust boundaries:Stage C: Sanity Check
Purpose: Verify findings against actual source code.Gates Applied
- GATE-3 [CHECKLIST]: Update checklist with verification
- GATE-5 [FULL-COVERAGE]: Check all code, no sampling
- GATE-6 [PROOF]: Show actual code verbatim
Verification Checks
- File exists at stated path
- Code matches VERBATIM at stated line (not paraphrased)
- Source→sink flow is real (not hypothetical)
- Code is reachable (function is actually called)
Output
findings.json with sanity_check field added:
Stage D: Ruling
Purpose: Make final exploitability determination based on all evidence.Gates Applied
- GATE-3 [CHECKLIST]: Document ruling decisions
- GATE-5 [FULL-COVERAGE]: Rule on all findings
- GATE-6 [PROOF]: Justify ruling with evidence
Ruling Criteria
Findings areruled_out if:
- Failed sanity check
- Requires impossible preconditions
- Protected by effective mitigations
- Attack paths have PROXIMITY ≤ 2
confirmed if:
- Passed sanity check
- Realistic exploitation path exists
- No effective protections
- Attack paths have PROXIMITY ≥ 6
Output
findings.json with ruling field:
Status Values
Confirmed- Exploitable, proceed to Stage ERuled Out- Not exploitable, stop here
Stage E: Feasibility
Purpose: Binary constraint analysis for memory corruption vulnerabilities.Scope: Stage E only applies to memory corruption types (buffer overflow, format string, UAF, etc.). Web/injection vulnerabilities stop at Stage D.
Memory Corruption Types
Stage E applies to:buffer_overflowheap_overflowstack_overflowformat_stringuse_after_freedouble_freeinteger_overflowout_of_bounds_readout_of_bounds_write
Binary Analysis
Integrates withpackages/exploit_feasibility for:
- Protection detection: ASLR, DEP, RELRO, stack canaries
- Constraint analysis: Bad bytes, null terminators
- Gadget availability: ROP gadgets, syscall availability
- Verdict: Likely / Difficult / Unlikely
Execution
Output
findings.json with feasibility and final_status:
Final Status Mapping
CLI Usage
Full Pipeline
Run complete validation from scratch:With Pre-existing Findings
Validate findings from scanner output (skips Stage 0 and A):With Binary for Stage E
Skip Stage E
Custom Working Directory
Python API
Orchestrator
Convenience Function
SARIF Input Support
The validation pipeline automatically converts SARIF format:SARIF Conversion
- Rule ID normalization:
engine.semgrep.rules.crypto.weak-hash→weak_hash - CWE mapping:
CWE-89→sql_injection - Deduplication: By file:line:vuln_type
- Logical locations: Extracts function names
- Severity mapping: SARIF levels → internal severity
Validation Report
Final output:validation-report.md
Output Style Guide
Per RAPTOR’s style conventions:Human-Readable Status
- ✅
Exploitable(notEXPLOITABLE) - ✅
Confirmed(notCONFIRMED) - ✅
Ruled Out(notRULED_OUT) - ✅
Proven/Disproven(notPROVEN/DISPROVEN)
No Colored Indicators
- ❌ Don’t use: 🔴/🟢 (perspective-dependent)
- ✅ Use: Plain text or
### Exploitable (7 findings) - ✅ Other emojis OK: ⚠️, ✓, etc.
Best Practices
Stage E requires binary: If no compiled binary is available, Stage E is skipped. Memory corruption findings will be marked
Confirmed without feasibility analysis.Troubleshooting
Stage A produces all “not_disproven”
This is normal for complex vulnerabilities. Stage B will analyze them systematically.Stage C sanity checks fail
Common causes:- Scanner output has stale file paths
- Code changed since scanning
- Scanner hallucinated the finding
Stage E skipped unexpectedly
Check:- Binary path is correct:
--binary /path/to/binary - Binary is executable:
chmod +x /path/to/binary - Vulnerability type is memory corruption
Integration Examples
From Semgrep
From CodeQL
From Autonomous Mode
Validation runs automatically in/agentic:
See Also
- Static Analysis - Generate findings for validation
- CodeQL Analysis - Semantic analysis with dataflow
- Binary Fuzzing - Dynamic testing
- Exploit Feasibility - Stage E binary analysis (coming soon)