Phase 5: Security Testing AI-Generated Code · 60 min · Z3 SMT solver · COBALT pipeline · AxiomGuard
Formal Verification with Z3
Don't guess. Prove. Z3 turns 'might be vulnerable' into 'is exploitable.'
Hiring signal: Engineers who can apply Z3 SMT solvers for formal verification of AI-generated code demonstrate cutting-edge security verification skills valued by security-focused teams.
What you will learn
- Understand how Z3 SMT solvers encode code behavior as formal constraints
- Explain the COBALT analysis pipeline for AI code verification
- Apply Z3 satisfiability witnesses to prove exploitability
- Understand AxiomGuard (deterministic Z3 verification with zero false positives)
- Understand Chiasmus (MCP server for formal verification) and ProvekIt (LLM+Z3 verifier for TypeScript)
The Problem
SAST tools guess. Z3 proves. This lesson covers how Z3 SMT solvers encode AI-generated code as formal constraints and mathematically prove whether vulnerabilities exist. We cover the COBALT analysis pipeline, Z3 satisfiability witnesses, and three tools built on Z3: AxiomGuard, Chiasmus, and ProvekIt.
How Z3 Works
Z3 is an SMT (Satisfiability Modulo Theories) solver developed by Microsoft Research. It takes logical constraints and determines if they're satisfiable (there exists a solution) or unsatisfiable (no solution exists).
The Verification Process
AI-generated code
↓
1. Parse → AST (Abstract Syntax Tree)
↓
2. Encode → Z3 constraints (formal formulas)
↓
3. Add exploit conditions (e.g., "buffer overflow exists")
↓
4. Solve → Z3 checks satisfiability
↓
5a. SAT (satisfiable) → Vulnerability PROVEN
→ Z3 produces a witness (concrete exploit input)
↓
5b. UNSAT (unsatisfiable) → Code PROVEN safe
→ No exploit input exists
Example: Buffer Overflow Verification
# AI-generated code (potentially vulnerable)
def copy_data(buffer, data):
for i in range(len(data)):
buffer[i] = data[i]
return buffer
# Z3 encoding:
# buffer_size = 10 (symbolic)
# data_length = symbolic (unknown)
# constraint: exists i such that i >= buffer_size
# Z3 finds: data_length = 15, i = 10 → buffer overflow!
# Witness: data = [0]*15, buffer = [0]*10
Z3 doesn't guess that a buffer overflow might exist. It proves that for data_length=15 and buffer_size=10, the loop writes beyond the buffer. The witness (data=[0]*15, buffer=[0]*10) is a concrete exploit input.
Unlock the full lesson
You've read the first 2 sections. The rest of this lesson covers The COBALT Analysis Pipeline, Z3-Based Tools, Build It — plus a hands-on lab, quiz, and project artifact.
Create a free account to unlock Phase 0 and Phase 1 of every course — no credit card.
Browse all courses · View pricing · DeVenture Academy