Lab: Garak Setup and First Scan
Install and configure garak, the LLM vulnerability scanner, then run your first automated scan against a local model to discover common vulnerabilities.
Prerequisites
- Python 3.10+ with pip
- Ollama running locally with the
llama3.2model pulled - At least 4GB of available disk space for garak and its dependencies
- Basic command-line familiarity
ollama pull llama3.2Background
Garak (Generative AI Red-teaming and Assessment Kit) is an automated tool for probing LLM vulnerabilities. It sends a curated set of adversarial prompts to a target model, measures the responses, and reports which vulnerabilities were detected. Think of it as a penetration testing tool specifically designed for language models.
Lab Exercises
Step 1: Install Garak
Install garak and verify the installation.
#!/usr/bin/env python3 """Verify garak installation and list available components.""" import subprocess import sys def run_command(cmd: list[str], description: str) -> str: """Run a shell command and return output.""" print(f"\n{'='*50}") print(f"Running: {description}") print(f"Command: {' '.join(cmd)}") print('='*50) result = subprocess.run( cmd, capture_output=True, text=True, timeout=120, ) if result.returncode != 0: print(f"STDERR: {result.stderr[:500]}") return f"FAILED: {result.stderr[:200]}" output = result.stdout.strip() print(output[:500] if output else "(no output)") return output if __name__ == "__main__": # Step 1: Check if garak is installed print("Checking garak installation...\n") version_output = run_command( [sys.executable, "-m", "garak", "--version"], "Check garak version" ) if "FAILED" in version_output: print("\nGarak not installed. Installing now...") install_output = run_command( [sys.executable, "-m", "pip", "install", "garak"], "Install garak" ) # Re-check version version_output = run_command( [sys.executable, "-m", "garak", "--version"], "Verify garak version" ) # Step 2: List available generators run_command( [sys.executable, "-m", "garak", "--list_generators"], "List available generators (model connectors)" ) # Step 3: List available probes run_command( [sys.executable, "-m", "garak", "--list_probes"], "List available probes (attack categories)" ) print("\n\nGarak installation verified successfully!") print("Key components:") print(" - Generators: Connect to target models (Ollama, OpenAI, etc.)") print(" - Probes: Adversarial prompt categories to test") print(" - Detectors: Analyze responses for vulnerabilities") print(" - Harnesses: Orchestrate the testing pipeline")pip install garak python install_garak.pyGarak has four main components: generators (how to connect to models), probes (what attacks to try), detectors (how to evaluate responses), and harnesses (how to orchestrate the test). Understanding this architecture helps you customize scans.
Step 2: Configure Garak for Ollama
Set up garak to target your local Ollama model.
#!/usr/bin/env python3 """Configure and verify garak connection to Ollama.""" import subprocess import sys import json def test_ollama_connection(): """Verify Ollama is running and the model is available.""" import urllib.request try: req = urllib.request.Request("http://localhost:11434/api/tags") with urllib.request.urlopen(req, timeout=5) as resp: data = json.loads(resp.read().decode()) models = [m["name"] for m in data.get("models", [])] print(f"Ollama is running. Available models: {models}") if any("llama3.2" in m for m in models): print("llama3.2 model is available.") return True else: print("WARNING: llama3.2 not found. Pull it with: ollama pull llama3.2") return False except Exception as e: print(f"Cannot connect to Ollama: {e}") print("Start Ollama with: ollama serve") return False def test_garak_generator(): """Test that garak can connect to the Ollama generator.""" print("\nTesting garak OllamaGenerator connection...") # Run a minimal garak probe to test connectivity result = subprocess.run( [ sys.executable, "-m", "garak", "--model_type", "ollama", "--model_name", "llama3.2", "--probes", "blank.BlankPrompt", "--generations", "1", ], capture_output=True, text=True, timeout=120, ) if result.returncode == 0: print("Garak successfully connected to Ollama!") print(f"Output: {result.stdout[-500:]}") return True else: print(f"Connection test failed.") print(f"Stdout: {result.stdout[-300:]}") print(f"Stderr: {result.stderr[-300:]}") return False if __name__ == "__main__": print("=== Garak + Ollama Configuration Test ===\n") ollama_ok = test_ollama_connection() if not ollama_ok: print("\nFix Ollama first, then re-run this script.") sys.exit(1) garak_ok = test_garak_generator() if garak_ok: print("\n\nConfiguration complete! Ready to run scans.") print("\nQuick reference:") print(" Generator: ollama") print(" Model: llama3.2") print(" API: http://localhost:11434") else: print("\nTroubleshooting:") print(" 1. Ensure Ollama is running: ollama serve") print(" 2. Ensure model is pulled: ollama pull llama3.2") print(" 3. Check garak version: python -m garak --version")python configure_garak.pyThis script verifies that both Ollama and garak are properly configured and can communicate with each other.
Step 3: Run Your First Vulnerability Scan
Execute a focused scan targeting prompt injection vulnerabilities.
#!/usr/bin/env python3 """Run a focused garak scan for prompt injection vulnerabilities.""" import subprocess import sys import json from pathlib import Path def run_garak_scan(probes: list[str], generations: int = 3) -> str: """Run a garak scan with specified probes.""" probe_str = ",".join(probes) print(f"Starting garak scan...") print(f" Probes: {probe_str}") print(f" Generations per probe: {generations}") print(f" Model: llama3.2 (Ollama)") print(" This may take several minutes...\n") result = subprocess.run( [ sys.executable, "-m", "garak", "--model_type", "ollama", "--model_name", "llama3.2", "--probes", probe_str, "--generations", str(generations), ], capture_output=True, text=True, timeout=600, ) print("STDOUT (last 1000 chars):") print(result.stdout[-1000:]) if result.stderr: print("\nSTDERR (last 500 chars):") print(result.stderr[-500:]) return result.stdout def find_latest_report() -> Path | None: """Find the most recent garak report file.""" garak_dir = Path.home() / ".local" / "share" / "garak" if not garak_dir.exists(): # Try alternative locations for alt in [Path("garak_runs"), Path.home() / "garak_runs"]: if alt.exists(): garak_dir = alt break report_files = list(garak_dir.rglob("*.report.jsonl")) if report_files: return max(report_files, key=lambda p: p.stat().st_mtime) return None if __name__ == "__main__": print("=== First Garak Vulnerability Scan ===\n") # Run a focused scan on prompt injection probes probes = [ "promptinject.HijackHateHumansMini", "promptinject.HijackKillHumansMini", ] output = run_garak_scan(probes, generations=3) # Try to find and display the report report = find_latest_report() if report: print(f"\nReport file: {report}") print("\nScan results:") with open(report) as f: for line in f: try: entry = json.loads(line.strip()) if "eval" in entry: probe = entry.get("probe", "unknown") score = entry.get("score", "N/A") print(f" Probe: {probe} | Score: {score}") except json.JSONDecodeError: continue else: print("\nReport file not found. Check garak output above for results.")python first_scan.pyGarak reports scores for each probe, where lower scores indicate more vulnerability. Review the output to see which prompt injection techniques the model is susceptible to.
Step 4: Run a Broader Scan
Expand the scan to cover additional vulnerability categories.
#!/usr/bin/env python3 """Run a broader garak scan covering multiple vulnerability categories.""" import subprocess import sys # Common garak probe categories for beginner red teaming SCAN_CONFIGS = [ { "name": "Prompt Injection", "probes": ["promptinject.HijackHateHumansMini"], "description": "Tests basic prompt injection and hijacking", }, { "name": "Encoding Attacks", "probes": ["encoding.InjectBase64"], "description": "Tests if encoded payloads bypass safety", }, { "name": "Known Jailbreaks", "probes": ["knownbadsignatures.LDNOOBW"], "description": "Tests known bad content generation", }, ] def run_single_scan(name: str, probes: list[str], desc: str): """Run a single scan category.""" probe_str = ",".join(probes) print(f"\n{'='*50}") print(f"Category: {name}") print(f"Description: {desc}") print(f"Probes: {probe_str}") print(f"{'='*50}\n") result = subprocess.run( [ sys.executable, "-m", "garak", "--model_type", "ollama", "--model_name", "llama3.2", "--probes", probe_str, "--generations", "2", ], capture_output=True, text=True, timeout=300, ) # Extract key results from output output_lines = result.stdout.strip().split("\n") for line in output_lines[-20:]: if any(kw in line.lower() for kw in ["pass", "fail", "score", "result"]): print(f" {line.strip()}") if result.returncode != 0: print(f" Warning: scan returned non-zero exit code") if result.stderr: print(f" Error: {result.stderr[-200:]}") if __name__ == "__main__": print("=== Broad Vulnerability Scan ===") print(f"Running {len(SCAN_CONFIGS)} scan categories...\n") for config in SCAN_CONFIGS: run_single_scan( config["name"], config["probes"], config["description"], ) print("\n\n=== Scan Complete ===") print("Review results above for each category.") print("Scores closer to 0 indicate more vulnerability.") print("Scores closer to 1 indicate better resistance.") print("\nNext steps:") print(" 1. Investigate any low-scoring categories") print(" 2. Run deeper scans on vulnerable areas") print(" 3. Compare results across different models")python broad_scan.pyThe broad scan covers multiple attack categories. Compare results across categories to identify which vulnerability families the model is most susceptible to.
Step 5: Analyze and Export Results
Parse garak's output reports and create a summary dashboard.
#!/usr/bin/env python3 """Analyze garak scan results and create a summary report.""" import json from pathlib import Path from datetime import datetime def find_reports() -> list[Path]: """Find all garak report files.""" search_dirs = [ Path.home() / ".local" / "share" / "garak", Path("garak_runs"), Path.home() / "garak_runs", Path.home() / ".garak", ] reports = [] for d in search_dirs: if d.exists(): reports.extend(d.rglob("*.report.jsonl")) return sorted(reports, key=lambda p: p.stat().st_mtime, reverse=True) def parse_report(report_path: Path) -> list[dict]: """Parse a garak JSONL report file.""" entries = [] with open(report_path) as f: for line in f: line = line.strip() if line: try: entries.append(json.loads(line)) except json.JSONDecodeError: continue return entries def generate_summary(entries: list[dict]) -> str: """Generate a readable summary from report entries.""" lines = [ "# Garak Scan Summary Report", f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}", "", ] # Group by probe probes = {} for entry in entries: probe = entry.get("probe", "unknown") if probe not in probes: probes[probe] = [] probes[probe].append(entry) if not probes: lines.append("No probe results found in report.") return "\n".join(lines) lines.extend([ "## Results by Probe", "", "| Probe | Attempts | Detections | Score |", "|-------|----------|------------|-------|", ]) for probe_name, probe_entries in sorted(probes.items()): attempts = len(probe_entries) # Calculate average score if available scores = [e.get("score", None) for e in probe_entries if "score" in e] if scores: avg_score = sum(s for s in scores if s is not None) / len(scores) detections = sum(1 for s in scores if s is not None and s < 0.5) else: avg_score = -1 detections = 0 score_str = f"{avg_score:.2f}" if avg_score >= 0 else "N/A" lines.append(f"| {probe_name} | {attempts} | {detections} | {score_str} |") lines.extend([ "", "## Interpretation", "- **Score < 0.3**: High vulnerability - model is easily exploited", "- **Score 0.3-0.7**: Moderate - some attacks succeed", "- **Score > 0.7**: Low vulnerability - model resists most attacks", "", "## Recommendations", "- Focus manual testing on probes with scores < 0.5", "- Compare results across model versions", "- Run targeted deep scans on vulnerable categories", ]) return "\n".join(lines) if __name__ == "__main__": print("=== Garak Results Analysis ===\n") reports = find_reports() if not reports: print("No garak report files found.") print("Run a scan first with the previous scripts.") print("\nExpected report locations:") print(" ~/.local/share/garak/") print(" ./garak_runs/") else: print(f"Found {len(reports)} report(s).") latest = reports[0] print(f"Analyzing: {latest}\n") entries = parse_report(latest) summary = generate_summary(entries) print(summary) # Save report with open("garak_summary.md", "w") as f: f.write(summary) print(f"\nSummary saved to garak_summary.md")python analyze_results.pyThe summary report provides a quick overview of the model's vulnerability profile. Low-scoring probes indicate areas where the model is most susceptible and should be prioritized for deeper manual testing.
Real-World Implications
Garak is valuable for production LLM security because:
- Baseline coverage: Automated scanning provides broad baseline vulnerability assessment quickly
- Reproducibility: Scans can be re-run after model updates to verify fixes and catch regressions
- CI/CD integration: Garak can be integrated into deployment pipelines to gate model releases on security thresholds
- Standardized reporting: Structured output enables consistent tracking of security posture over time
Troubleshooting
| Issue | Solution |
|---|---|
garak command not found | Install with pip install garak or run as python -m garak |
| Connection refused to Ollama | Ensure Ollama is running: ollama serve |
| Model not found | Pull the model: ollama pull llama3.2 |
| Scan times out | Reduce --generations or use fewer probes |
| No report files generated | Check ~/.local/share/garak/ or the current directory |
| Import errors | Ensure garak and its dependencies are installed in the same Python environment |
Related Topics
- PyRIT Setup -- Set up Microsoft's PyRIT red teaming framework
- Promptfoo Setup -- Set up promptfoo for LLM evaluation
- Ollama Setup -- Configure local model hosting with Ollama
- Injection Techniques Survey -- Manual techniques that complement automated scanning
- Inspect AI Setup -- Set up Inspect AI for evaluation
References
- Garak GitHub Repository -- https://github.com/NVIDIA/garak -- Official source code and documentation
- "Garak: A Framework for Security Probing Large Language Models" -- derczynski et al. (2024) -- Technical paper describing garak's architecture
- OWASP Top 10 for LLM Applications -- OWASP (2025) -- The vulnerability categories garak tests align with OWASP guidance
What are the four main components of garak's architecture?
Why should automated scanning with garak precede manual red teaming?