OWASP LLM Top 10 Scanner

Application Securityv1.0.0

Dedicated SAST scanner for LLM/AI applications with 73 rules covering all 10 OWASP LLM Top 10 categories plus 16 dependency CVEs

73
rules
10
categories
16
cves

01Overview

Generative-AI features ship faster than security teams can review them, and the classic SAST tools that guard web apps have no concept of a prompt, an agent tool, a vector store, or a model file. The OWASP LLM Top 10 Scanner closes that gap. It is a single, self-contained Python file (owasp_llm_scanner.py, ~2,000 lines, zero third-party dependencies) that statically analyzes AI/LLM application source, config, and dependency manifests against the OWASP Top 10 for Large Language Model Applications (2025) — from prompt injection and system-prompt leakage to excessive agency, insecure output handling, and unbounded consumption.

Unlike a generic linter, every rule is written for the way LLM code actually looks: f-strings and template literals that splice user input into prompts, LangChain agents invoked on raw request bodies, torch.load() and from_pretrained(trust_remote_code=True) that turn a model file into remote code execution, ShellTool / PythonREPLTool wired into an autonomous agent, LLM output piped into eval()/exec()/subprocess/innerHTML, and ChatOpenAI clients instantiated with no max_tokens. It reads Python, JavaScript/TypeScript, .env, and YAML for pattern findings, and parses requirements.txt, Pipfile, pyproject.toml, and package.json to flag known-vulnerable LLM libraries (LangChain, transformers, torch, gradio, mlflow, litellm, llama-index, ollama, and more) by CVE and version range.

It is built for AppSec engineers, ML/platform teams, and CI/CD owners who need a fast, dependency-free gate they can drop into any pipeline. Findings carry a severity, CWE mapping, the offending line, a plain-English risk description, and concrete remediation. Output is human-readable color console or machine-readable JSON, and the process exits non-zero on any CRITICAL/HIGH finding so a build can fail the moment risky AI code is introduced.

It is notable for being a purpose-built LLM SAST scanner rather than a bolt-on ruleset: all ten OWASP LLM categories are represented, the checks map to the concrete APIs of the modern AI stack, and the whole thing runs anywhere Python 3.8+ runs with nothing to install.

02Key Capabilities

Full OWASP LLM Top 10 (2025) coverage

Ships rules for every category LLM01 through LLM10, so a single scan reports against the entire framework rather than a subset.

LLM-native prompt-injection detection

Flags user input spliced into prompts via f-strings, .format(), string concatenation, template literals, and PromptTemplate/agent invocations across Python and JS/TS.

Insecure model-loading and RCE checks

Catches torch.load() without weights_only, trust_remote_code=True in from_pretrained/load_dataset, allow_dangerous_deserialization, and pickle-based chain loading.

Improper output-handling sinks

Detects LLM output flowing into eval/exec, SQL execute, subprocess/os.system, Jinja2 |safe, innerHTML, document.write, and React dangerouslySetInnerHTML.

Excessive-agency guardrail checks

Warns when ShellTool, PythonREPLTool, unrestricted tools, unbounded AgentExecutor loops, or human_input_mode=NEVER hand too much power to an agent.

Dependency CVE scanning for the AI stack

Parses requirements.txt, Pipfile, pyproject.toml, and package.json to match LangChain, transformers, torch, gradio, mlflow, litellm and others against known CVEs by version range.

Secret and system-prompt leakage detection

Finds hardcoded OpenAI/Anthropic/HuggingFace keys, keys and system prompts in .env/YAML/client-side code, and prompts leaked via verbose mode, logs, or API responses.

Unbounded-consumption and cost controls

Flags LLM clients without max_tokens, API calls without timeouts, and generate/invoke calls inside while-True/setInterval loops that can run away on cost.

Vector and embedding weakness checks

Detects unauthenticated ChromaDB clients, unsanitized user input written to vector stores, and similarity_search results fed straight into prompts (indirect injection).

Multi-format input support

One scanner reads .py/.pyw, .js/.jsx/.ts/.tsx/.mjs/.cjs, .env, .yaml/.yml, and Python/Node dependency manifests from a file or a whole directory tree.

CI/CD-ready reporting

Color-coded console output plus a structured JSON report, severity filtering, and an exit code of 1 on CRITICAL/HIGH findings to gate builds.

Zero-install, single-file deployment

The entire scanner is one standard-library-only Python file, so it drops into any environment or pipeline with nothing to pip install.

03Architecture

The scanner is a single Python module organized as data-driven rule sets fed through a shared regex engine. A central LLMScanner class walks the target, dispatches each file to a handler by extension, and either line-matches SAST/config rules or parses a dependency manifest against a CVE database; every hit becomes a Finding that flows into console and JSON reporters. There is no external SAST framework — pattern rules, the CVE table, the version-range matcher, and the reporters are all self-contained.

1
Rule sets (data layer)
Module-level lists LLM_PYTHON_SAST_RULES (45), LLM_JS_SAST_RULES (16), LLM_ENV_RULES (4) and LLM_YAML_RULES (4), each a dict of id/category/severity/regex/description/cwe/recommendation.
2
CVE knowledge base
LLM_VULNERABLE_PACKAGES (14 Python packages) and LLM_NPM_VULNERABLE_PACKAGES (3 npm packages) map library names to affected version ranges, CVE ids, severity, and fix versions.
3
LLMScanner orchestrator
scan_path -> _scan_directory (os.walk with a SKIP_DIRS denylist) -> _dispatch_file routes each path to the right handler by suffix/name.
4
File-type handlers
_scan_python/_scan_js/_scan_env/_scan_yaml run the SAST engine, while _scan_requirements/_scan_pipfile/_scan_pyproject_toml/_scan_package_json parse manifests and add an unpinned-package heuristic (LLM03-REQ-001).
5
SAST regex engine
_sast_scan compiles each rule's pattern once, iterates file lines, skips pure comment lines, and emits a Finding on any match.
6
Version-range CVE matcher
_parse_ver and _version_in_range normalize versions to int tuples and evaluate constraints like '<0.0.247' or '>=2.0,<2.15.0' to decide if a dependency is vulnerable.
7
Finding model and reporters
A Finding object carries rule/severity/file/line/CWE/CVE; summary, filter_severity, print_report (ANSI color) and save_json render results and drive the exit code.

04Project Structure

owasp_llm_scanner.pyThe scanner itself — rule sets, CVE database, LLMScanner engine, reporters, and CLI in one ~1,998-line file.
tests/samples/vulnerable_agent.pyIntentionally vulnerable Python AI/agent fixture that exercises the Python LLM SAST rules.
tests/samples/requirements.txtFixture pinning known-vulnerable LLM packages to trigger the dependency CVE checks.
tests/samples/gap_services_bad.yamlYAML config fixture for the YAML rules (system prompts, hardcoded keys, trust_remote_code, missing token limits).
tests/samples/.envEnvironment-file fixture with LLM API keys, ML-tracking creds, and database secrets for the .env rules.
python_scanner.pySibling general-purpose Python SAST scanner (shares the single-file architecture pattern).
mern_scanner.pySibling JS/TS (MERN) SAST scanner in the same repository.
java_scanner.pySibling Java/Maven/Gradle/WAR SAST scanner.
php_scanner.pySibling PHP SAST scanner.
README.mdRepository documentation covering every scanner, inputs, categories, and usage.
CLAUDE.mdArchitecture and contributor guide describing the shared scanner pattern and rule-ID conventions.
banner.svgProject banner asset; LICENSE holds the MIT license.

05Security Controls

LLM01 Prompt Injection
Detects user input interpolated into prompts via f-strings, concatenation, .format(), PromptTemplate.from_template, ChatPromptTemplate, and agent run/invoke on raw request data (Python + JS/TS).
LLM02 Sensitive Information Disclosure
Flags hardcoded OpenAI/Anthropic/HuggingFace keys, PII field names passed to LLM calls, and LLM responses logged or printed; .env rules catch API keys and DB creds that can reach model context.
LLM03 Supply Chain
torch.load without weights_only, trust_remote_code=True, unpinned HuggingFace revisions, HTTP model downloads without integrity checks, plus a version-range CVE database of 14 Python + 3 npm LLM libraries.
LLM04 Data & Model Poisoning
Detects trust_remote_code in load_dataset, unvalidated training-data paths from argv, unsanitized user feedback written to training corpora, and remote datasets loaded without integrity verification.
LLM05 Improper Output Handling
Catches LLM output flowing into eval/exec, cursor.execute (SQLi), subprocess/os.system (command injection), Jinja2 |safe, innerHTML, document.write, Function(), and React dangerouslySetInnerHTML.
LLM06 Excessive Agency
Flags ShellTool/BashTool and PythonREPLTool/CodeInterpreter exposed to agents, AgentExecutor without max_iterations, allow_dangerous_tools=True, write-capable FileManagementTool, and human_input_mode=NEVER.
LLM07 System Prompt Leakage
Detects verbose=True agents, system prompts returned in API responses, logged, hardcoded in client-side JS, or stored in .env/YAML config.
LLM08 Vector & Embedding Weaknesses
Flags ChromaDB clients created without authentication, unsanitized user input stored in vector DBs, and similarity_search results used directly in prompts (indirect injection).
LLM09 & LLM10 Misinformation and Unbounded Consumption
Flags temperature>0.9 and unvalidated streaming, plus LLM clients without max_tokens, API calls without timeouts, and generate/invoke inside while-True/setInterval loops.
CWE-mapped findings
Every rule carries a CWE (e.g., CWE-74, CWE-502, CWE-94, CWE-78, CWE-89, CWE-79, CWE-400, CWE-312, CWE-1104) and a concrete remediation, with severity from CRITICAL to LOW.

06Technology Stack

Language
Python 3.8+
Dependencies
None — standard library only (re, os, sys, json, argparse, pathlib, datetime)
Detection engine
Line-based compiled-regex matching + version-range constraint evaluator
Inputs
.py/.pyw, .js/.jsx/.ts/.tsx/.mjs/.cjs, .env, .yaml/.yml, requirements.txt, Pipfile, pyproject.toml, package.json
Output
ANSI color console report and structured JSON (--json)
Testing
Intentionally vulnerable fixtures under tests/samples/ (no test framework)
CI
None in-repo; exit-code gating is designed for external pipelines
Deployment
Single self-contained file — copy and run, no install

07Quick Start

$ python3 owasp_llm_scanner.py /path/to/ai-project
$ python3 owasp_llm_scanner.py agent.py --verbose
$ python3 owasp_llm_scanner.py requirements.txt
$ python3 owasp_llm_scanner.py /path/to/project --severity HIGH --json report.json
$ python3 owasp_llm_scanner.py tests/samples/    # run the bundled vulnerable fixtures

08Compliance & Frameworks

OWASP Top 10 for LLM Applications (2025)
Rules are organized by and cover all ten categories, LLM01 through LLM10.
CWE
Each finding is tagged with a Common Weakness Enumeration id (e.g., CWE-74, CWE-502, CWE-94, CWE-78, CWE-89, CWE-79, CWE-400, CWE-312, CWE-1104).
CVE
Dependency findings reference specific CVE identifiers with affected/fixed version ranges for LLM libraries.
GDPR / HIPAA (data protection)
The PII-to-LLM rule (LLM02-004) explicitly calls out that sending personal data to external LLM APIs may violate GDPR, HIPAA, and other data-protection regulations.

09Integrations & Outputs

JSON report export (--json) for downstream toolingExit code 1 on CRITICAL/HIGH for CI/CD build gatingSeverity filtering (--severity CRITICAL|HIGH|MEDIUM|LOW|INFO)Dependency manifests: requirements.txt, Pipfile, pyproject.toml, package.jsonConfig inputs: .env and YAML LLM/agent configsANSI color console output for local and pipeline logs

Explore OWASP LLM Top 10 Scanner

Full source, documentation, and deployment guides live on GitHub.