Vibe-Coded Python Security Linter
Catches security antipatterns that AI code generators commonly introduce. AI has predictable failure modes that traditional linters like Bandit don't specifically target.
AI-generated code has a ~25% rate of security flaws (DEV Community 2026). These aren't random bugs - AI makes predictable mistakes:
- Using MD5/SHA1 for password hashing
- Hardcoding secrets in obvious variable names
- Using
eval()on user input - SQL injection via f-strings
shell=Truein subprocess calls- Non-constant-time password comparison
- YAML deserialization without SafeLoader
Traditional linters catch some of these, but vibeguard focuses specifically on AI's failure patterns.
pip install vibeguardOr run directly (zero dependencies):
curl -O https://raw.githubusercontent.com/kriskimmerle/vibeguard/main/vibeguard.py
python vibeguard.py app.py# Scan a single file
vibeguard app.py
# Scan a directory
vibeguard src/
# CI mode - fail if score below 75
vibeguard . --check --min-score 75
# JSON output
vibeguard . --format json
# Ignore specific rules
vibeguard . --ignore VG16 --ignore VG03======================================================================
vibeguard - Vibe-Coded Python Security Linter
======================================================================
Files scanned: 5
Total findings: 4
Security Score: 55/100 (Grade: D)
Findings by severity:
CRITICAL: 2
HIGH: 1
MEDIUM: 1
----------------------------------------------------------------------
📄 app.py
🔴 Line 12: [VG01] CRITICAL
Using hashlib.md5 for password hashing - use bcrypt, argon2, or scrypt instead
Fix: Replace with: from passlib.hash import argon2; argon2.hash(password)
🔴 Line 28: [VG06] CRITICAL
SQL query using f-string - SQL injection vulnerability
Fix: Use parameterized queries: cursor.execute('SELECT * FROM t WHERE id = ?', (id,))
🟠 Line 45: [VG07] HIGH
shell=True with subprocess - command injection risk
Fix: Use shell=False with a list of arguments: subprocess.run(['cmd', 'arg1'])
======================================================================
⚠️ Security issues found - review and fix before deployment!
| Rule | Severity | Description |
|---|---|---|
| VG01 | CRITICAL | MD5/SHA1 used for password hashing |
| VG02 | HIGH | ECB mode in encryption (insecure) |
| VG03 | HIGH | Weak random (random module) for security |
| VG04 | HIGH | Hardcoded IV/salt/nonce |
| VG05 | CRITICAL | eval/exec/compile usage |
| VG06 | CRITICAL | SQL injection via string formatting |
| VG07 | HIGH | shell=True or os.system() |
| VG08 | CRITICAL | Unsafe deserialization (pickle, marshal) |
| VG09 | CRITICAL | Hardcoded secrets/keys |
| VG10 | HIGH | Non-constant-time secret comparison |
| VG12 | MEDIUM | CORS allows all origins (*) |
| VG14 | HIGH | Sensitive data in URL parameters |
| VG15 | HIGH | Debug mode enabled |
| VG16 | INFO | LLM output usage (review for sanitization) |
| VG17 | CRITICAL | YAML load without SafeLoader |
usage: vibeguard [-h] [--format {text,json}] [--check] [--min-score MIN_SCORE]
[--ignore RULE] [--exclude PATH] [--verbose] [--version]
[path]
positional arguments:
path File or directory to scan (default: .)
options:
-h, --help show this help message and exit
--format, -f {text,json}
Output format
--check Exit with code 1 if score below threshold
--min-score MIN_SCORE Minimum score for --check (default: 60)
--ignore, -i RULE Rules to ignore (can repeat)
--exclude, -e PATH Paths to exclude (can repeat)
--verbose, -v Show code snippets
--version, -V Show version
- name: Security scan with vibeguard
run: |
pip install vibeguard
vibeguard . --check --min-score 75repos:
- repo: local
hooks:
- id: vibeguard
name: vibeguard security check
entry: vibeguard
language: python
types: [python]
args: [--check, --min-score, "75"]Bandit is excellent for general Python security. vibeguard focuses on patterns AI specifically gets wrong:
| Pattern | Bandit | vibeguard |
|---|---|---|
| MD5 usage | ✅ Warns about weak hash | ✅ Warns specifically when used for passwords |
| Hardcoded secrets | ✅ Catches common AI variable names | |
| SQL injection | ✅ Basic detection | ✅ Detects f-strings and .format() in execute() |
| LLM output handling | ❌ | ✅ Flags for review |
| YAML SafeLoader | ✅ | ✅ |
| Non-constant-time comparison | ❌ | ✅ Detects password/token comparisons |
Use both tools together for comprehensive coverage.
from vibeguard import scan_file, scan_directory, calculate_score
# Scan a file
result = scan_file(Path("app.py"))
for finding in result.findings:
print(f"{finding.rule}: {finding.message}")
# Scan a directory
results = scan_directory(Path("src/"))
all_findings = [f for r in results for f in r.findings]
score = calculate_score(all_findings)
print(f"Security score: {score}/100")- Fork the repository
- Add new detection rules in
VibeGuardVisitor - Add tests for new rules
- Submit a pull request
- Vibe Coding Could Cause Catastrophic 'Explosions' - The New Stack
- Securing Vibe Coding Tools - Palo Alto Unit42
- How to Secure Vibe Coded Applications - DEV Community
MIT License - see LICENSE for details.