MCP server for OWASP Top 10 (2025) security scanning of Python and Next.js codebases
Project description
owasp-scanner
MCP server for OWASP Top 10 (2025) security scanning of Python and Next.js codebases.
Uses regex pre-filtering + optional LLM reasoning to find vulnerabilities that pattern-matching tools miss, with a persistent finding workflow that makes security knowledge accumulate instead of evaporate.
88 rules. 20 tools. Local SQLite persistence. LLM is optional.
Installation
# With pip
pip install owasp-scanner
# With uv
uv tool install owasp-scanner
# With LLM support (optional)
pip install owasp-scanner[llm]
MCP Setup
Add to your Claude configuration:
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"owasp-scanner": {
"command": "uvx",
"args": ["owasp-scanner"]
}
}
}
Claude Code (project or user settings):
{
"mcpServers": {
"owasp-scanner": {
"command": "uvx",
"args": ["owasp-scanner"]
}
}
}
With LLM scanning enabled:
{
"mcpServers": {
"owasp-scanner": {
"command": "uvx",
"args": ["owasp-scanner[llm]"],
"env": {
"OWASP_LLM_ENABLED": "true",
"OWASP_OPENAI_API_KEY": "sk-..."
}
}
}
}
Quick Start
CLI mode:
# Scan a project directory
owasp-scanner --scan /path/to/project
# Fail CI if high-severity issues found
owasp-scanner --scan /path/to/project --fail-on=high
Scanned: /path/to/project
Findings: 7 (7 new)
critical: 1
high: 2
medium: 4
FAIL: 3 findings at high or above.
MCP mode (via Claude):
"Scan this project for security issues"
The scanner runs automatically when loaded as an MCP server. Claude can call any of the 20 tools directly.
Tools
Scanning
| Tool | Description |
|---|---|
scan_directory(path, mode, exclude, git_diff_base) |
Scan a directory. Set git_diff_base="main" to scan only changed files. |
scan_file(path, mode) |
Scan a single file. Modes: regex, deep, llm, hybrid. |
scan_config(path, framework) |
Scan config files (Django, FastAPI, Next.js). |
scan_dependencies(path) |
Check dependencies for known CVEs via pip-audit. |
scan_boundary(path) |
Analyze Next.js Server-to-Client Component prop crossings for data leaks. |
Findings
| Tool | Description |
|---|---|
list_findings(status, severity, category) |
List findings with filters. |
get_finding(id) |
Full detail + audit trail for a finding. |
create_finding(...) |
Manually create a finding from review or pentesting. |
update_finding(id, status, notes) |
Triage: mark as fixed, accepted, or false positive. |
delete_finding(id) |
Remove a finding. |
verify_fix(id) |
Re-check if the pattern that triggered a finding is gone. |
LLM
| Tool | Description |
|---|---|
llm_triage(finding_ids, auto_update) |
Batch LLM triage — identifies true/false positives. |
Reporting
| Tool | Description |
|---|---|
get_summary() |
Dashboard: counts by status, category, severity. |
export_report(scan_id, output_path) |
Markdown report with executive summary. |
export_sarif(scan_id, output_path) |
SARIF 2.1.0 for GitHub/VS Code/CI integration. |
get_trends(days) |
Open/closed over time, mean time to remediation. |
Utility
| Tool | Description |
|---|---|
list_scans(limit) |
Scan history. |
create_baseline(path) |
Snapshot current findings as the baseline. |
health_check() |
Server status, rule count, database info. |
get_errors(error_id, tool_name) |
Recent scanner errors for debugging. |
Scanning Modes
| Mode | What happens | Cost |
|---|---|---|
regex |
88 regex patterns, instant | Free |
deep |
Framework detection, endpoint extraction, security checklist for LLM reasoning | Free |
llm |
LLM scans each file with framework-specific context | ~$0.01-0.02/project |
hybrid |
Regex first, LLM triage (marks false positives), then LLM design review | ~$0.02-0.05/project |
Default is regex. The scanner works fully offline without an API key.
OWASP 2025 Rule Coverage
| Category | Python | Next.js | LLM focus |
|---|---|---|---|
| A01 Broken Access Control | 4 (auth, path traversal, SSRF) | 5 (route handler, server action, mass assignment) | Missing auth, IDOR |
| A02 Security Misconfiguration | 7 (DEBUG, ALLOWED_HOSTS, CORS, XXE) | 3 (NEXT_PUBLIC secrets, image SSRF) | Config gaps |
| A03 Supply Chain | 2 (unpinned deps, git installs) | -- | Dep hygiene, SBOM |
| A04 Cryptographic Failures | 7 (MD5, SHA-1, random, ECB, DES) | 2 (Math.random, cookies) | Key management |
| A05 Injection | 8 (SQL, pickle, eval, yaml, subprocess) | 6 (XSS, Prisma, command injection) | ORM injection |
| A06 Insecure Design | -- | 1 (middleware matcher) | Primary LLM category |
| A07 Authentication | 9 (secrets detection across all file types) | 2 (DB strings, API keys) | Missing MFA |
| A08 Integrity Failures | 4 (CDN SRI, marshal, shelve, jsonpickle) | -- | Mass assignment |
| A09 Logging Failures | 2 (sensitive data in logs, log injection) | -- | Missing audit logging |
| A10 Exceptional Conditions | 5 (bare except, fail-open, timeout) | 2 (empty catch, error leak) | Fail-open, transactions |
Environment Variables
| Variable | Default | Description |
|---|---|---|
OWASP_DATA_DIR |
~/.owasp-scanner |
Database and logs directory |
OWASP_MAX_FILE_SIZE_KB |
500 |
Skip files larger than this |
OWASP_LLM_ENABLED |
false |
Enable LLM scanning modes |
OWASP_OPENAI_API_KEY |
-- | OpenAI API key for LLM modes |
OWASP_LLM_MODEL |
gpt-5.4-nano |
Model for LLM scanning |
OWASP_LLM_BASE_URL |
-- | Override for Ollama, Azure, or vLLM |
LLM Setup
LLM scanning is optional. The scanner works fully with regex mode (free, no API key needed).
To enable LLM modes (llm, hybrid, llm_triage):
export OWASP_LLM_ENABLED=true
export OWASP_OPENAI_API_KEY=sk-...
For local models via Ollama:
export OWASP_LLM_ENABLED=true
export OWASP_LLM_BASE_URL=http://localhost:11434/v1
export OWASP_OPENAI_API_KEY=ollama # any non-empty string
export OWASP_LLM_MODEL=llama3.1
Troubleshooting
No findings on a scan:
- Check
OWASP_MAX_FILE_SIZE_KB(default 500 KB) — large files are skipped - Check exclude patterns —
.owaspignorein the project root can suppress matches - Run
health_check()to verify the scanner is working
LLM mode not working:
- Verify
OWASP_LLM_ENABLED=trueandOWASP_OPENAI_API_KEYare set - Run
health_check()— it reports whether the LLM is available - Check
get_errors()for API errors
Permission errors:
- The data directory (
~/.owasp-scanner/) must be writable - The database file is created with mode 0600 (owner-only read/write)
Adding Custom Rules
Rules are regex patterns with OWASP metadata. To add a new rule:
- Add a
Rule(...)entry tosrc/owasp_scanner/rules/patterns.py(Python) ornextjs_patterns.py(Next.js) - Add a positive match test + negative match test to
tests/test_rules.py - Run
uv run python -m pytest tests/test_rules.py -v
For external rules without modifying source, place YAML files in ~/.owasp-scanner/rules/:
- id: CUSTOM-001
owasp_category: A05
severity: high
title: "Custom injection pattern"
description: "Description of the vulnerability"
pattern: "dangerous_function\\("
file_glob: "*.py"
suggested_fix: "Use safe_function() instead"
Development
git clone https://github.com/mfbaig35r/owasp-scanner.git
cd owasp-scanner
uv sync --all-extras
uv run python -m pytest tests/ -v --tb=short # 370 tests
uv run ruff check src/ tests/ # lint
License
MIT
Project details
Release history Release notifications | RSS feed
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 owasp_scanner-0.2.0.tar.gz.
File metadata
- Download URL: owasp_scanner-0.2.0.tar.gz
- Upload date:
- Size: 116.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f03d87034412485f0526933619836fffa45506d3f25db105e68bb246758e3166
|
|
| MD5 |
94697089c19d6685eaff3e81bb00e902
|
|
| BLAKE2b-256 |
d2f4db7920f908d7dfdc74eb112dbee26082f4c12236ffd5981569a911bdf0a6
|
Provenance
The following attestation bundles were made for owasp_scanner-0.2.0.tar.gz:
Publisher:
publish.yml on mfbaig35r/owasp-scanner
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
owasp_scanner-0.2.0.tar.gz -
Subject digest:
f03d87034412485f0526933619836fffa45506d3f25db105e68bb246758e3166 - Sigstore transparency entry: 1402596568
- Sigstore integration time:
-
Permalink:
mfbaig35r/owasp-scanner@c5d25ab248916035087b4a86ba10fbc5a5b0ea74 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/mfbaig35r
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c5d25ab248916035087b4a86ba10fbc5a5b0ea74 -
Trigger Event:
release
-
Statement type:
File details
Details for the file owasp_scanner-0.2.0-py3-none-any.whl.
File metadata
- Download URL: owasp_scanner-0.2.0-py3-none-any.whl
- Upload date:
- Size: 76.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0b0e8c2bd5ac8d7198dd216a5b5b0b861b1812969df215e37f512fa91e71d7a
|
|
| MD5 |
814d96fc71e7f795b0905f0429d38092
|
|
| BLAKE2b-256 |
198051c9dcf2132d73fc58b8d148515fc78bb25fb08b002e078c2ccec43315a3
|
Provenance
The following attestation bundles were made for owasp_scanner-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on mfbaig35r/owasp-scanner
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
owasp_scanner-0.2.0-py3-none-any.whl -
Subject digest:
e0b0e8c2bd5ac8d7198dd216a5b5b0b861b1812969df215e37f512fa91e71d7a - Sigstore transparency entry: 1402596675
- Sigstore integration time:
-
Permalink:
mfbaig35r/owasp-scanner@c5d25ab248916035087b4a86ba10fbc5a5b0ea74 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/mfbaig35r
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c5d25ab248916035087b4a86ba10fbc5a5b0ea74 -
Trigger Event:
release
-
Statement type: