PyGuard
AST-based static security analysis tool for Python and more — with AI-powered explanations.
PyGuard scans source code for security vulnerabilities without executing it. It combines deterministic rule-based detection with optional AI-assisted remediation suggestions via Google Gemini or local Ollama.
Publisher: eenverylmz | Repository: github.com/eenverylmz/PyGuard
Features
- AST-based analysis — structural code analysis, not text scanning
- 26 built-in vulnerability rules — covering OWASP Top 10 and CWEs
- CWE-driven auto-rule generator — synthesize new rules from CWE definitions
- Modular rule engine — add custom rules as standalone
.py files
- AI explanations — Gemini (cloud) or Ollama (local) powered remediation suggestions
- Multi-language support — Python (AST) + JS, Java, Go, PHP, Rust (pattern-based)
- VS Code extension — real-time scanning with sidebar panel and Problems pane
- Persistent bridge — zero startup overhead after first activation
- Debounced auto-scan — 400ms debounce prevents rapid re-analysis storms
Installation
git clone https://github.com/eenverylmz/PyGuard.git
cd PyGuard
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
VS Code Extension: Search PyGuard in the Extensions panel or visit the Marketplace.
CLI Usage
# Scan a single file
python cli.py path/to/your_file.py
# Scan a directory
python cli.py path/to/project/
# JSON output
python cli.py path/to/your_file.py --json
# With AI explanations (uses provider from PYGUARD_AI_PROVIDER env var)
python cli.py path/to/your_file.py --ai
# Force Ollama
PYGUARD_AI_PROVIDER=ollama python cli.py path/to/your_file.py --ai
# Force Gemini
PYGUARD_AI_PROVIDER=gemini python cli.py path/to/your_file.py --ai
AI Backend
PyGuard supports two AI backends for vulnerability explanations:
Ollama (Local — Default)
No API key needed. Runs entirely on your machine.
- Install Ollama: https://ollama.com
- Pull a model:
ollama pull llama3.2
- Start Ollama:
ollama serve
- Set in VS Code:
pyguard.aiProvider → ollama
Environment variables:
PYGUARD_AI_PROVIDER=ollama
PYGUARD_OLLAMA_MODEL=llama3.2 (default)
PYGUARD_OLLAMA_URL=http://localhost:11434 (default)
Gemini (Cloud)
Requires a Google AI Studio API key.
- Get a key from https://aistudio.google.com/apikey
- Set in VS Code:
pyguard.aiProvider → gemini
- Run
PyGuard: Set Gemini API Key from the command palette
Environment variables:
PYGUARD_AI_PROVIDER=gemini
GEMINI_API_KEY=...
GEMINI_MODEL=models/gemini-2.5-flash-lite (default)
Detected Vulnerability Classes (26 Rules)
Python Rules (AST)
| # |
ID |
Name |
Severity |
CWE |
| 1 |
PYG002 |
eval() usage |
Critical |
CWE-94 |
| 2 |
PYG003 |
Unsafe yaml.load() |
High |
CWE-94 |
| 3 |
PYG004 |
Unsafe subprocess shell=True |
High |
CWE-78 |
| 4 |
PYG005 |
Insecure pickle deserialization |
Critical |
CWE-502 |
| 5 |
PYG006 |
Weak crypto hash (MD5/SHA1) |
Medium |
CWE-328 |
| 6 |
PYG007 |
Insecure random |
Medium |
CWE-338 |
| 7 |
PYG008 |
Bare except clause |
Low |
CWE-703 |
| 8 |
PYG009 |
Unsafe os.system() |
High |
CWE-78 |
| 9 |
PYG010 |
Unsafe subprocess shell |
High |
CWE-78 |
| 10 |
PYG011 |
Unsafe builtins (compile, globals) |
Medium |
CWE-94 |
| 11 |
PYG012 |
SQL Injection (Python) |
Critical |
CWE-89 |
| 12 |
PYG013 |
Path Traversal |
High |
CWE-22 |
| 13 |
PYG014 |
SSRF |
High |
CWE-918 |
| 14 |
PYG015 |
XXE Injection |
High |
CWE-611 |
| 15 |
PYG016 |
Insecure JWT |
Critical |
CWE-347 |
| 16 |
PYG020 |
Dangerous builtins (eval/exec/__import__) |
Critical |
CWE-94 |
| 17 |
PYG021 |
SQL Injection (f-string / dynamic) |
Critical |
CWE-89 |
| 18 |
PYG022 |
Unsafe deserialization (pickle) |
Critical |
CWE-502 |
| 19 |
PYG023 |
Server-Side Template Injection |
Critical |
CWE-1336 |
| 20 |
PYG024 |
Hardcoded credential |
High |
CWE-798 |
| 21 |
PYG025 |
SSL/TLS verification disabled |
High |
CWE-295 |
| 22 |
PYG026 |
Unsafe os.popen() |
High |
CWE-78 |
| 23 |
PYG027 |
Weak ciphers (DES/RC4/ECB) |
High |
CWE-327 |
| 24 |
PYG028 |
Misc security (input/temp/mktemp) |
Medium |
CWE-20/338/377 |
| 25 |
PYG029 |
Open redirect / header injection |
Medium |
CWE-601/113/614 |
| 26 |
PYG030 |
Deprecated module (crypt/imp) |
Low |
CWE-477 |
Pattern-based (Python + JS + Java + Go + PHP + Rust)
| ID |
Detects |
| PYG900 |
Hardcoded secrets (AWS tokens, GitHub PATs, Stripe keys, high-entropy strings) |
| PYG950 |
Injection patterns (eval, shell_exec, Runtime.exec, exec.Command) |
VS Code Extension
Install: Search PyGuard in the Extensions panel.
Features:
- Auto-scan on save (configurable via
pyguard.analyzeOnSave)
- Manual scan via
Ctrl+Shift+P → PyGuard: Analyze
- Findings in the Problems pane with inline highlights
- Sidebar panel with severity badges, CWE references, code snippets
- Click any finding to jump to the exact line
- AI provider selection via
Ctrl+Shift+P → PyGuard: Select AI Provider
Settings:
| Setting |
Default |
Description |
pyguard.analyzeOnSave |
true |
Auto-analyze on file save |
pyguard.pythonPath |
python3 |
Python interpreter path |
pyguard.aiEnabled |
false |
Enable AI-powered explanations |
pyguard.aiProvider |
ollama |
AI backend: ollama (local) or gemini (cloud) |
pyguard.ollamaModel |
llama3.2 |
Ollama model name |
pyguard.ollamaUrl |
http://localhost:11434 |
Ollama server URL |
pyguard.geminiModel |
models/gemini-2.5-flash-lite |
Gemini model name |
Architecture
VS Code (TypeScript)
extension.ts → persistent bridge, debounce, activate/deactivate
SidebarProvider.ts → WebView with postMessage incremental updates
aiKey.ts → AI provider selection, Gemini key management
│
│ spawn / JSON stdin/stdout
▼
vscode_bridge.py → persistent process (stays alive across saves)
│
▼
Python Engine
core/analyzer.py → language routing, AST parse
core/AST_parser.py → import alias collection, call resolution
core/generic_scanner.py → regex-based secret/injection scanning
engine/rule_engine.py → node-type dispatch, ctx injection, rule running
rules/ → 26 security rule modules (PYG002–PYG030)
rules/auto_rule_generator.py → CWE-driven rule synthesis (23 CWEs)
ai/client.py → unified AI provider router (Ollama + Gemini)
ai/ollama_client.py → local LLM inference via Ollama
Writing Custom Rules
Drop a .py file in rules/ — PyGuard picks it up automatically:
# rules/my_rule.py
import ast
from core.result import Vulnerability
RULE_ID = "PYG100"
def check(node: ast.Call, ctx=None) -> list:
findings = []
if isinstance(node, ast.Call):
# detection logic
findings.append(Vulnerability(
rule_id=RULE_ID, name="My Rule",
severity="high", description="...",
line=getattr(node, "lineno", 1),
cwe="CWE-XXX", code="",
))
return findings
Tips:
- Type-annotate the
node param (e.g., node: ast.Call) for faster dispatch
- Use
ctx.get("import_aliases", {}) for resolved import aliases
- Return empty list for no findings (never return
None)
Auto-Rule Generator
Generate rules from CWE definitions:
# Generate one rule
python3 rules/auto_rule_generator.py --cwe CWE-89
# Generate all 23 CWE rules
python3 rules/auto_rule_generator.py --all --output-dir rules/ --overwrite
# List available CWEs
python3 rules/auto_rule_generator.py --list-cwes
# Validate a generated rule
python3 rules/auto_rule_generator.py --validate rules/sql_injection.py
Add new CWEs by editing the CWE_DATABASE dict in rules/auto_rule_generator.py.
- Persistent bridge — Python process stays alive (no 200-500ms startup per save)
- 400ms debounce — prevents rapid re-analysis storms
- postMessage sidebar — incremental DOM updates instead of full HTML regeneration
- Node-type dispatch — rules pre-categorized by AST node type at load time (
O(nodes * relevant_rules) instead of O(nodes * all_rules))
- Cached signatures —
inspect.signature() called once at module load, not per-node-per-rule
Requirements
Project Structure
PyGuard/
├── src/ # VS Code extension (TypeScript)
│ ├── extension.ts # Persistent bridge, debounce, activate
│ ├── SidebarProvider.ts # WebView panel via postMessage
│ ├── aiKey.ts # AI provider selection, Gemini key management
│ └── *.map # Source maps
├── ai/ # AI backends
│ ├── client.py # Unified provider router (Ollama + Gemini)
│ └── ollama_client.py # Local LLM via Ollama
├── core/ # Analysis core
│ ├── analyzer.py # Language routing, AST parse
│ ├── AST_parser.py # Alias collection, call resolution
│ ├── generic_scanner.py # Multi-language secret/injection scanning
│ └── result.py # Vulnerability dataclass
├── engine/ # Rule engine
│ └── rule_engine.py # Node-type dispatch, ctx injection
├── rules/ # 26 security rules + auto-generator
│ ├── unsafe_os_system.py
│ ├── sql_injection.py
│ ├── auto_rule_generator.py
│ └── ... (24 more)
├── samples/ # Test files for all languages
├── assets/ # Extension icons
├── cli.py # CLI entry point
├── vscode_bridge.py # Persistent JSON bridge
├── package.json # Extension manifest
├── tsconfig.json # TypeScript config
└── requirements.txt # Python dependencies
Changelog
v1.0.1 — 2026-06-01
New features:
- Ollama (local AI) support — use local LLMs instead of Gemini cloud API
- Unified AI provider router —
ai/client.py routes to Ollama or Gemini via PYGUARD_AI_PROVIDER
- AI provider selection — new
PyGuard: Select AI Provider command in VS Code
- New settings —
pyguard.aiProvider, pyguard.ollamaModel, pyguard.ollamaUrl, pyguard.geminiModel
pyguard.aiEnabled default changed to false (opt-in AI)
v1.0.0 — 2026-06-01
New rules (11): SQL injection, dangerous builtins, unsafe deserialization, SSTI, hardcoded credentials, SSL bypass, os.popen(), weak ciphers, misc security (input/PRNG/tempfile), open redirect/header injection, deprecated modules.
New features:
- Persistent bridge process (zero startup overhead on save)
- 400ms debounced auto-scan
- postMessage-based incremental sidebar updates
- Click-to-navigate from sidebar to source line
- CWE-driven auto-rule generator (23 CWEs)
- Node-type dispatch in rule engine
- Import alias resolution in auto-generated rules
Performance: 10x faster analysis after first activation (persistent bridge).
Disclaimer
PyGuard is for educational and defensive security purposes only. Scan only code you own or have permission to analyze.
Author
Enver Yilmaz
LinkedIn | GitHub