Security scanner for AI-generated code
Project description
vigil
Security scanner for AI-generated code. Fast, deterministic, no LLMs required.
vigil is a CLI static analysis tool that detects vulnerabilities and risk patterns specific to code generated by AI agents — problems that Semgrep, Snyk, and CodeQL were not designed to catch.
It detects hallucinated dependencies (slopsquatting), insecure auth patterns, hardcoded placeholder secrets, and empty test theater. It's a complement to your existing security tools, not a replacement.
Status: v0.6.0 — Full integration + end-to-end tests + QA audit. All 4 analyzers, 4 output formats, 24 of 26 rules implemented. 1518 tests.
The Problem
- 20% of packages recommended by LLMs don't exist in any registry (University of Texas/Virginia Tech, 2025)
- 58% of hallucinated package names are repeatable — attackers can register them (Socket Research, 2025)
- 45% of LLM-generated code contains security flaws (Veracode, 2025)
Existing scanners check for known CVEs in real packages. vigil checks whether the packages even exist, whether secrets are just copy-pasted placeholders, and whether tests actually assert anything.
Quick Start
# Install
pip install vigil-ai-cli
# Scan your project
vigil scan src/
# Check dependencies only
vigil deps --verify
# Analyze test quality
vigil tests tests/
# Generate config
vigil init --strategy standard
# List all rules
vigil rules
What It Detects
Dependency Hallucination (CAT-01)
Verifies that every dependency actually exists in PyPI/npm and isn't suspicious.
| Rule | Severity | Description |
|---|---|---|
| DEP-001 | CRITICAL | Package does not exist in registry (hallucinated) |
| DEP-002 | HIGH | Package was created less than 30 days ago |
| DEP-003 | HIGH | Package name is very similar to a popular package (typosquatting) |
| DEP-004 | MEDIUM | Package has very few weekly downloads |
| DEP-005 | MEDIUM | Package has no linked source repository |
| DEP-006 | HIGH | Import in code for a module not in declared dependencies |
| DEP-007 | CRITICAL | Specified version does not exist in registry |
Auth & Permission Patterns (CAT-02)
Detects insecure authentication patterns commonly generated by AI agents.
| Rule | Severity | Description |
|---|---|---|
| AUTH-001 | HIGH | Sensitive endpoint without authentication middleware |
| AUTH-002 | HIGH | DELETE/PUT endpoint without authorization |
| AUTH-003 | MEDIUM | JWT with lifetime exceeding 24 hours |
| AUTH-004 | CRITICAL | Hardcoded JWT secret with placeholder value |
| AUTH-005 | HIGH | CORS configured with * (allow all origins) |
| AUTH-006 | MEDIUM | Cookie without httpOnly/secure/sameSite flags |
| AUTH-007 | MEDIUM | Password comparison without timing-safe function |
Secrets & Credentials (CAT-03)
Detects secrets that AI agents copy from examples or generate insecurely.
| Rule | Severity | Description |
|---|---|---|
| SEC-001 | CRITICAL | Placeholder secret from .env.example or docs |
| SEC-002 | CRITICAL | Hardcoded secret with low entropy |
| SEC-003 | CRITICAL | Connection string with embedded credentials |
| SEC-004 | HIGH | Sensitive env variable with hardcoded default |
| SEC-005 | HIGH | Secret file not listed in .gitignore |
| SEC-006 | CRITICAL | Value copied verbatim from .env.example |
Test Quality (CAT-06)
Detects test theater — tests that pass but verify nothing.
| Rule | Severity | Description |
|---|---|---|
| TEST-001 | HIGH | Test function without any assertions |
| TEST-002 | MEDIUM | Trivial assertion (assert x is not None, assertTrue(True)) |
| TEST-003 | MEDIUM | Test catches all exceptions without verifying type |
| TEST-004 | LOW | Skipped test without justification |
| TEST-005 | MEDIUM | API test that doesn't verify status code |
| TEST-006 | MEDIUM | Mock returns exactly what implementation would calculate |
Output Formats
# Terminal (default)
vigil scan src/
# JSON (programmatic)
vigil scan src/ --format json --output report.json
# SARIF (GitHub/GitLab Code Scanning)
vigil scan src/ --format sarif --output report.sarif
# JUnit XML (CI dashboards)
vigil scan src/ --format junit --output report.xml
CI/CD Integration
GitHub Actions
- name: Security scan (vigil)
run: |
pip install vigil-ai-cli
vigil scan src/ --format sarif --output vigil.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: vigil.sarif
Pre-commit Hook
# .pre-commit-config.yaml
repos:
- repo: https://github.com/org/vigil
rev: v0.6.0
hooks:
- id: vigil
args: [scan, --changed-only]
Configuration
Generate a config file with vigil init:
vigil init # standard defaults
vigil init --strategy strict # stricter thresholds
vigil init --strategy relaxed # more permissive
This creates .vigil.yaml in your project root. See .vigil.example.yaml for all available options.
Key Options
# Minimum severity to fail (exit code 1)
fail_on: "high" # critical | high | medium | low
# Languages to scan
languages: [python, javascript]
# Dependency checks
deps:
verify_registry: true
min_age_days: 30
similarity_threshold: 0.85
offline_mode: false
# Disable or adjust specific rules
rules:
DEP-004:
severity: "low"
AUTH-003:
enabled: false
CLI Reference
vigil scan [PATHS] [OPTIONS] Scan code for AI-generated security issues
vigil deps [PATH] [OPTIONS] Check dependencies for hallucinated packages
vigil tests [PATHS] [OPTIONS] Analyze test quality
vigil init [PATH] [OPTIONS] Generate .vigil.yaml configuration
vigil rules List all available rules
Exit Codes
| Code | Meaning |
|---|---|
| 0 | No findings above threshold |
| 1 | Findings found above threshold |
| 2 | Execution error |
Common Flags
| Flag | Description |
|---|---|
--format, -f |
Output format: human, json, junit, sarif |
--output, -o |
Write output to file |
--fail-on |
Minimum severity to fail: critical, high, medium, low |
--category, -C |
Only run specific categories |
--rule, -r / --exclude-rule, -R |
Include/exclude specific rules |
--language, -l |
Only scan specific languages |
--offline |
Skip HTTP requests to registries |
--changed-only |
Only scan files changed since last commit |
--verbose, -v |
Verbose output |
What vigil Is NOT
- Not a replacement for Semgrep/Snyk/SonarQube. It's a complement. Use them together.
- Not a vulnerability database (SCA). It doesn't track CVEs. For that, use Snyk or Trivy.
- Not AI-powered. It's deterministic: static rules, heuristics, registry verification. No API costs, no hallucinations of its own.
- Not specific to any AI agent. Works the same whether code came from Cursor, Claude Code, Copilot, or ChatGPT.
OWASP Alignment
| OWASP Risk | vigil Coverage |
|---|---|
| LLM02 — Sensitive Information Disclosure | SEC-001 to SEC-006 |
| LLM03 — Supply Chain Vulnerabilities | DEP-001 to DEP-007 |
| LLM06 — Excessive Agency | AUTH-001 to AUTH-007 |
Requirements
- Python 3.12+
- No external services required (registry checks are optional with
--offline)
Development
# Clone and setup
git clone https://github.com/org/vigil.git
cd vigil
python3.12 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
# Run tests (1518 tests)
pytest tests/ -v
# Run with coverage (~99% on reports module)
pytest tests/ -v --cov=vigil
# Lint
ruff check src/ tests/
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vigil_ai_cli-0.6.0.tar.gz.
File metadata
- Download URL: vigil_ai_cli-0.6.0.tar.gz
- Upload date:
- Size: 80.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e57bd9cb49ad84b2e09b5c97e41d45510bd66ada071bbdb9bef99a1487b6acba
|
|
| MD5 |
36a7859ff4e7d04551b85e364487b363
|
|
| BLAKE2b-256 |
413544dac9608ac4b49f336e46a7f8ff49a45feea41214f77e864dbfd134351e
|
File details
Details for the file vigil_ai_cli-0.6.0-py3-none-any.whl.
File metadata
- Download URL: vigil_ai_cli-0.6.0-py3-none-any.whl
- Upload date:
- Size: 70.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29fe8136de25409a6116b20f1a98b53867bf4326bdcd67e6906084b425bdafdb
|
|
| MD5 |
cf61081fd2763de955eb7d65f74ee547
|
|
| BLAKE2b-256 |
cadf8f3b93fd4fe3253ec6c0822f3f4f229db552b046cd6bd089878628fcb3c6
|