SecureAI-Scan
The AI security scanner that proves its findings.
SecureAI-Scan finds LLM, MCP, and RAG vulnerabilities in TypeScript, JavaScript, and Python — and shows you the evidence: the exact source → flow → sink path for every dataflow finding, resolved through real imports, not keyword matching.
As of v0.4.0, it's the first scanner mapped to all three OWASP AI security frameworks — the LLM Top 10, the Top 10 for Agentic Applications (2026), and the MCP Top 10 — with a coverage matrix in every threat model showing exactly which risks are checked and which are runtime concerns.
▌ HIGH AI001 Prompt injection via user input
PROVEN LLM01 Prompt Injection
source src/chat.ts:8 request data `req.body.input`
flow src/chat.ts:13 passed as `systemPrompt`
sink src/chat.ts:10 openai.chat.completions.create — system role (OpenAI)
fix Keep system prompts static; pass user input as a user-role message.
Why this scanner is different
- Evidence tiers, not noise. Every finding is
proven(traced dataflow or parsed config fact),likely(resolved sink, one heuristic hop), orheuristic. A default scan shows only proven + likely. Heuristics are opt-in via--paranoid. - Import-resolved detection. A call is only an "LLM call" if it resolves to a real SDK import (
openai,@anthropic-ai/sdk,ai,@google/genai, LangChain, Bedrock, …). Your Google Maps client will never be flagged as an LLM again. - Precision-gated in CI. The test suite asserts every vulnerable fixture fires and every safe fixture stays clean. A false positive on the safe corpus fails the build.
- SARIF for GitHub code scanning.
--output report.sarifputs findings inline on pull requests and in the Security tab. - AI-BOM.
secureai-scan bom .inventories every SDK, model ID, vector store, agent framework, and MCP server in your repo — zero-false-positive by construction, mapped to OWASP LLM Top 10 / EU AI Act documentation needs. - MCP config scanning. Parses
.mcp.json,claude_desktop_config.json,.cursor/mcp.json: unpinnednpx -yservers, inline secrets, plaintext HTTP transports. - MCP tool-poisoning detection. Catches the pattern behind the WhatsApp MCP rug-pull and postmark-mcp backdoor — invisible Unicode, agent-directed injection phrases, and cross-tool shadowing in tool names/descriptions, statically, before you ever run the server.
- Known-malicious package advisories. Checks every dependency and every MCP-launched package against a curated advisory list (documented backdoors, critical CVEs) — offline, on every scan, no flag required.
- Local-first. Nothing leaves your machine.
Get started in 30 seconds
npx --yes secureai-scan@latest scan .
TypeScript, JavaScript, Python, and MCP config files are scanned automatically.
Prefer to ask questions first? Try the free SecureAI-Scan AI Security Advisor on ChatGPT.
About to run an MCP server you found on GitHub or Twitter? Paste its tool description into MCP X-Ray first — checks it for hidden Unicode, injected instructions, and known-malicious packages in your browser, no install.
Commands
secureai-scan scan . # proven + likely findings
secureai-scan scan . --paranoid # include heuristic tier
secureai-scan scan . --output r.sarif # GitHub code scanning (also .html/.md/.json)
secureai-scan scan . --fail-on high # CI gate: exit 1 at/above severity
secureai-scan scan . --baseline .secureai-baseline.json # only new issues
secureai-scan bom . --output AI_BOM.md # AI Bill of Materials
secureai-scan explain AI001 # why + exploit + fix example
secureai-scan threat-model . # THREAT_MODEL.md for review
secureai-scan init # policy file + CI workflow
Suppress a reviewed finding in code:
// secureai-ignore AI001: reviewed, input sanitized via allowlist
GitHub Action
name: SecureAI-Scan
on: [pull_request]
permissions:
contents: read
security-events: write
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: akanthed/SecureAI-Scan@main
with:
fail-on: high
Findings appear as inline annotations on the PR and in the repository's Security tab. (secureai-scan init generates an equivalent workflow using the CLI directly.)
Scanning clean? Add the badge to your own README:
[](https://github.com/akanthed/SecureAI-Scan)
Rules
Every rule maps to the OWASP LLM Top 10 (2025) — plus, where applicable, the OWASP Top 10 for Agentic Applications (2026, ASI) and the OWASP MCP Top 10 (2025) — and, where relevant, an EU AI Act article. threat-model output includes a full coverage matrix across all three frameworks.
| Rule | What it proves | OWASP |
|---|---|---|
| AI001 | User input flows into a system/developer prompt (traced source → sink) | LLM01 |
| AI002 | Prompt content or secrets written to logs (in files that use an LLM SDK) | LLM02 |
| AI003 | LLM call in a request handler with no auth check before it | LLM10 |
| AI004 | Whole user/session object serialized into a prompt (field-picking is not flagged) | LLM02 |
| AI005 | LLM output reaches eval/exec/SQL/HTML sinks | LLM05 |
| AI006 | High-impact tools (delete, pay, deploy, …) exposed without an approval gate | LLM06 |
| AI007 | Retrieved RAG content interpolated into privileged prompts | LLM01 |
| AI008 | Secrets embedded in system prompt text | LLM07 |
| AI009 | Unbounded user input / missing token limits | LLM10 |
| AI010 | Fetched external content flows into prompts | LLM01 |
| AI011 | Agent output elevated to system-role in downstream calls | LLM06 |
| AI012 | LLM output parsed without schema validation | LLM05 |
| MCP001 | MCP tool metadata reaches the system prompt without validation | LLM01 |
| MCP002 | MCP server URL constructed from user input | LLM03 |
| MCP003 | MCP tool results elevated to system-role | LLM05 |
| MCP004 | MCP server launched as an unpinned npx -y package |
LLM03 |
| MCP005 | Secret inlined in a committed MCP config | LLM02 |
| MCP006 | MCP server over plaintext HTTP | LLM03 |
| MCP007 | Invisible/bidi Unicode hidden in MCP tool names or descriptions | LLM01 · MCP03 |
| MCP008 | Agent-directed injection phrases in MCP tool descriptions | LLM01 · MCP03 |
| MCP009 | A tool description that steers calls to a different tool (shadowing) | LLM01 · MCP03 |
| VEC001 | Vector search without a tenant/user filter | LLM08 |
| VEC002 | Unbounded or user-controlled search limit | LLM10 |
| VEC003 | User content ingested into a shared vector store | LLM04 |
| VEC004 | Ingestion without tenant/namespace tagging | LLM08 |
| DEP001 | Dependency name not found in the registry (opt-in --check-dependencies) |
LLM03 |
| DEP002 | Dependency name one edit away from a popular package (opt-in) | LLM03 |
| DEP003 | Dependency with a documented malicious release or critical CVE — checked offline on every scan (postmark-mcp, mcp-remote CVE-2025-6514, …) | LLM03 · MCP04 |
secureai-scan explain <RULE_ID> gives the exploit walkthrough and a before/after code example for any rule.
MCP server (use it from Claude)
The package ships an MCP server exposing scan_repository, explain_rule, and generate_bom:
{
"mcpServers": {
"secureai-scan": {
"command": "node",
"args": ["/path/to/secureai-scan/mcp-server/index.js"]
}
}
}
The precision contract
False positives kill scanners. SecureAI-Scan's rule engine follows three hard rules:
- Sinks are resolved through imports. If an identifier resolves to a module that is not an LLM SDK, it is definitively not an LLM call — no matter what it's named.
- Evidence is labeled, never blended. A traced dataflow and a word-proximity match are not the same thing, so they never share a tier.
- The safe corpus gates every release.
test-fixtures/safe/contains the patterns that used to cause false positives (redacted PII payloads, Google Maps clients, env-var API keys next to LLM clients, ordinary response logging). Any finding there fails the suite.
License
MIT © Akshay Kanthed
No comments yet
Be the first to share your take.