ai-security-scanner 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. ai_security_scanner-1.0.0/PKG-INFO +525 -0
  2. ai_security_scanner-1.0.0/README.md +494 -0
  3. ai_security_scanner-1.0.0/ai_security_scanner.egg-info/PKG-INFO +525 -0
  4. ai_security_scanner-1.0.0/ai_security_scanner.egg-info/SOURCES.txt +39 -0
  5. ai_security_scanner-1.0.0/ai_security_scanner.egg-info/dependency_links.txt +1 -0
  6. ai_security_scanner-1.0.0/ai_security_scanner.egg-info/entry_points.txt +2 -0
  7. ai_security_scanner-1.0.0/ai_security_scanner.egg-info/requires.txt +26 -0
  8. ai_security_scanner-1.0.0/ai_security_scanner.egg-info/top_level.txt +1 -0
  9. ai_security_scanner-1.0.0/aiscan/__init__.py +0 -0
  10. ai_security_scanner-1.0.0/aiscan/api/__init__.py +0 -0
  11. ai_security_scanner-1.0.0/aiscan/api/routes.py +180 -0
  12. ai_security_scanner-1.0.0/aiscan/cli.py +382 -0
  13. ai_security_scanner-1.0.0/aiscan/config.py +23 -0
  14. ai_security_scanner-1.0.0/aiscan/models.py +54 -0
  15. ai_security_scanner-1.0.0/aiscan/reporters/__init__.py +0 -0
  16. ai_security_scanner-1.0.0/aiscan/reporters/console_reporter.py +49 -0
  17. ai_security_scanner-1.0.0/aiscan/reporters/json_reporter.py +40 -0
  18. ai_security_scanner-1.0.0/aiscan/rules/__init__.py +0 -0
  19. ai_security_scanner-1.0.0/aiscan/rules/registry.py +429 -0
  20. ai_security_scanner-1.0.0/aiscan/scanners/__init__.py +0 -0
  21. ai_security_scanner-1.0.0/aiscan/scanners/agent_scanner.py +10 -0
  22. ai_security_scanner-1.0.0/aiscan/scanners/api_scanner.py +12 -0
  23. ai_security_scanner-1.0.0/aiscan/scanners/base_scanner.py +78 -0
  24. ai_security_scanner-1.0.0/aiscan/scanners/integration_scanner.py +7 -0
  25. ai_security_scanner-1.0.0/aiscan/scanners/mcp_scanner.py +7 -0
  26. ai_security_scanner-1.0.0/aiscan/scanners/prompt_scanner.py +7 -0
  27. ai_security_scanner-1.0.0/aiscan/scanners/tm_coding_standards_scanner.py +56 -0
  28. ai_security_scanner-1.0.0/aiscan/sdk/__init__.py +13 -0
  29. ai_security_scanner-1.0.0/aiscan/sdk/decorators.py +178 -0
  30. ai_security_scanner-1.0.0/aiscan/sdk/http_client.py +125 -0
  31. ai_security_scanner-1.0.0/aiscan/sdk/middleware.py +207 -0
  32. ai_security_scanner-1.0.0/aiscan/sdk/scanner.py +236 -0
  33. ai_security_scanner-1.0.0/aiscan/tm_coding_standards/__init__.py +0 -0
  34. ai_security_scanner-1.0.0/aiscan/tm_coding_standards/models.py +62 -0
  35. ai_security_scanner-1.0.0/aiscan/tm_coding_standards/registry.py +11 -0
  36. ai_security_scanner-1.0.0/aiscan/utils/__init__.py +0 -0
  37. ai_security_scanner-1.0.0/aiscan/utils/aggregator.py +16 -0
  38. ai_security_scanner-1.0.0/aiscan/utils/ai_checker.py +163 -0
  39. ai_security_scanner-1.0.0/pyproject.toml +45 -0
  40. ai_security_scanner-1.0.0/setup.cfg +4 -0
  41. ai_security_scanner-1.0.0/setup.py +30 -0
@@ -0,0 +1,525 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-security-scanner
3
+ Version: 1.0.0
4
+ Summary: AI Security Scanner — scan prompts, agents, APIs, MCP tools and integrations
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: typer>=0.12.0
8
+ Requires-Dist: rich>=13.7.0
9
+ Requires-Dist: pyyaml>=6.0.1
10
+ Requires-Dist: pydantic>=2.7.0
11
+ Requires-Dist: pydantic-settings>=2.2.0
12
+ Requires-Dist: anthropic>=0.28.0
13
+ Requires-Dist: openai>=1.30.0
14
+ Requires-Dist: python-dotenv>=1.0.0
15
+ Requires-Dist: structlog>=24.1.0
16
+ Requires-Dist: twine>=6.2.0
17
+ Requires-Dist: uvicorn>=0.49.0
18
+ Requires-Dist: fastapi>=0.136.3
19
+ Requires-Dist: python-multipart>=0.0.32
20
+ Provides-Extra: api
21
+ Requires-Dist: fastapi>=0.111.0; extra == "api"
22
+ Requires-Dist: uvicorn[standard]>=0.29.0; extra == "api"
23
+ Provides-Extra: vertex
24
+ Requires-Dist: google-cloud-aiplatform>=1.60.0; extra == "vertex"
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
27
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
28
+ Requires-Dist: httpx>=0.27.0; extra == "dev"
29
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
30
+ Dynamic: requires-python
31
+
32
+ # aiscan — AI Security Scanner
33
+
34
+ Scans **prompts**, **agents**, **APIs**, **MCP tools**, and **integrations** for security vulnerabilities — prompt injection, data leakage, tool abuse, and security risks.
35
+
36
+ 40 built-in rules + AI deep scan (Claude / GPT-4o / Gemini). Runs as a CLI, REST API, Python SDK, or middleware.
37
+
38
+ ---
39
+
40
+ ## Table of contents
41
+
42
+ - [Why aiscan](#why-aiscan)
43
+ - [Installation](#installation)
44
+ - [Quick start](#quick-start)
45
+ - [CLI commands](#cli-commands)
46
+ - [Scan types](#scan-types)
47
+ - [Rules reference](#rules-reference)
48
+ - [REST API](#rest-api)
49
+ - [Python SDK](#python-sdk)
50
+ - [Middleware](#middleware)
51
+ - [Decorators](#decorators)
52
+ - [HTTP client (other languages)](#http-client-other-languages)
53
+ - [CI/CD integration](#cicd-integration)
54
+ - [AI provider configuration](#ai-provider-configuration)
55
+ - [Suppressing false positives](#suppressing-false-positives)
56
+ - [Sample files](#sample-files)
57
+ - [Troubleshooting](#troubleshooting)
58
+
59
+ ---
60
+
61
+ ## Why aiscan
62
+
63
+ Traditional security tools (SonarQube, Snyk, Semgrep) were built before AI systems existed. They have no rules for prompt injection, agent tool permissions, or MCP tool definitions. aiscan fills that gap — it treats prompts, agent configs, and AI integrations as first-class security artifacts.
64
+
65
+ ---
66
+
67
+ ## Installation
68
+
69
+ ### From source
70
+
71
+ ```bash
72
+ git clone <your-repo-url>
73
+ cd aiscan-cli
74
+ pip install -r requirements-all.txt
75
+ pip install -e .
76
+ ```
77
+
78
+ ### Verify install
79
+
80
+ ```bash
81
+ aiscan version
82
+ ```
83
+
84
+ If `aiscan` command is not found, use `python -m aiscan.cli` instead everywhere below.
85
+
86
+ ---
87
+
88
+ ## Quick start
89
+
90
+ ```bash
91
+ # 1. Generate config
92
+ aiscan init
93
+
94
+ # 2. Add your API key to .env
95
+ # ANTHROPIC_API_KEY=sk-ant-...
96
+
97
+ # 3. Scan a file
98
+ aiscan scan my_prompt.txt
99
+ aiscan scan --type api openapi.yaml
100
+ aiscan scan --type mcp tool_config.json
101
+
102
+ # 4. Scan without AI (static rules only, no API key needed)
103
+ aiscan scan --no-ai openapi.yaml
104
+ ```
105
+
106
+ ---
107
+
108
+ ## CLI commands
109
+
110
+ ### `aiscan scan`
111
+
112
+ ```
113
+ Usage: aiscan scan [OPTIONS] FILES...
114
+
115
+ Options:
116
+ -t, --type TEXT Scan type: prompt | agent | api | mcp | integration | all | auto [default: auto]
117
+ -o, --output TEXT Output format: console | json | sarif [default: console]
118
+ -O, --out PATH Write output to file instead of stdout
119
+ -f, --fail-on TEXT Exit 1 if severity reached: critical | high | medium | none [default: high]
120
+ --no-ai Skip AI deep scan — static rules only
121
+ -q, --quiet Suppress output except errors
122
+ ```
123
+
124
+ **Examples:**
125
+
126
+ ```bash
127
+ # Auto-detect scan type from extension
128
+ aiscan scan system_prompt.txt
129
+ aiscan scan agent_config.yaml
130
+
131
+ # Explicit scan type
132
+ aiscan scan --type prompt system_prompt.txt
133
+ aiscan scan --type agent agent.yaml
134
+ aiscan scan --type api openapi.yaml
135
+ aiscan scan --type mcp tool.json
136
+ aiscan scan --type integration webhook_config.yaml
137
+
138
+ # Scan a whole directory
139
+ aiscan scan --type auto ./my-project/
140
+
141
+ # Run all 5 scanners on the same file
142
+ aiscan scan --type all config.yaml
143
+
144
+ # JSON / SARIF output
145
+ aiscan scan --type api openapi.yaml --output json
146
+ aiscan scan --type prompt prompts/ --output sarif --out results.sarif
147
+
148
+ # CI mode
149
+ aiscan scan --quiet --fail-on high prompts/ && echo "passed"
150
+ ```
151
+
152
+ ### `aiscan rules`
153
+
154
+ ```bash
155
+ aiscan rules # list all 40 rules
156
+ aiscan rules prompt # rules for prompt scan type
157
+ aiscan rules api --severity critical # filter by severity
158
+ ```
159
+
160
+ ### `aiscan init`
161
+
162
+ ```bash
163
+ aiscan init # creates .env for Claude
164
+ aiscan init --provider openai # pre-configure for OpenAI
165
+ aiscan init --force # overwrite existing .env
166
+ ```
167
+
168
+ ### `aiscan serve`
169
+
170
+ ```bash
171
+ aiscan serve # http://localhost:8000
172
+ aiscan serve --port 9000
173
+ aiscan serve --reload # dev mode, auto-restart
174
+ ```
175
+
176
+ ### `aiscan version`
177
+
178
+ ```bash
179
+ aiscan version
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Scan types
185
+
186
+ | Type | Detects | File extensions (auto-detect) |
187
+ |---|---|---|
188
+ | `prompt` | Prompt injection, PII leakage, jailbreaks | `.txt` `.md` `.py` `.js` `.ts` `.go` `.java` and more |
189
+ | `agent` | Wildcard tools, missing human approval, infinite loops | `.yaml` `.yml` |
190
+ | `api` | Hardcoded keys, wildcard CORS, missing auth | `.yaml` `.yml` `.json` |
191
+ | `mcp` | Wildcard permissions, code execution, missing rate limits | `.json` |
192
+ | `integration` | Default secrets, SSL disabled, data forwarding | `.env` `.toml` `.ini` `.cfg` |
193
+
194
+ ---
195
+
196
+ ## Rules reference
197
+
198
+ 40 rules total — 6 categories. Run `aiscan rules` to see the live list.
199
+
200
+ | Category | Rule IDs | Example |
201
+ |---|---|---|
202
+ | Prompt | `PI-001` `PI-002` `DL-001` `DL-002` `EX-001` | `ignore previous instructions` |
203
+ | Agent | `AG-001`–`AG-006` | `allow_all_tools: true` |
204
+ | API | `AK-001` `AK-002` `CO-001` `HT-001` `JW-001` `AU-001` | hardcoded `api_key` |
205
+ | MCP | `MC-001`–`MC-006` | `execute_code: true` |
206
+ | Integration | `IN-001`–`IN-006` | `webhook_secret: changeme` |
207
+ | Code | `CD-001`–`CD-012` | `eval()`, SQL injection via f-string |
208
+ | AI deep scan | `AI-SCAN` | Subtle issues caught by Claude/GPT-4o/Gemini |
209
+
210
+ ---
211
+
212
+ ## REST API
213
+
214
+ ```bash
215
+ aiscan serve
216
+ ```
217
+
218
+ | Method | Path | Description |
219
+ |---|---|---|
220
+ | GET | `/health` | Service status |
221
+ | POST | `/scan/prompt` | Scan prompt content |
222
+ | POST | `/scan/agent` | Scan agent config |
223
+ | POST | `/scan/api` | Scan API config or OpenAPI spec |
224
+ | POST | `/scan/mcp` | Scan MCP tool definition |
225
+ | POST | `/scan/integration` | Scan integration config |
226
+ | POST | `/scan/all` | Run all 5 scanners |
227
+ | GET | `/docs` | Swagger UI |
228
+
229
+ **Request:**
230
+ ```json
231
+ {"content": "file content as string", "filename": "openapi.yaml"}
232
+ ```
233
+
234
+ **Response:**
235
+ ```json
236
+ {
237
+ "scan_type": "api",
238
+ "passed": false,
239
+ "critical": 1, "high": 2, "medium": 0, "info": 0, "total": 3,
240
+ "findings": [
241
+ {
242
+ "rule_id": "AK-001",
243
+ "severity": "critical",
244
+ "threat": "security_risk",
245
+ "title": "Hardcoded secret or API key",
246
+ "detail": "Matched on line 5: ...",
247
+ "file": "config.yaml",
248
+ "line": 5,
249
+ "fix": "Move to environment variables or a secrets manager."
250
+ }
251
+ ]
252
+ }
253
+ ```
254
+
255
+ **curl example:**
256
+ ```bash
257
+ curl -X POST http://localhost:8000/scan/prompt \
258
+ -H "Content-Type: application/json" \
259
+ -d '{"content": "Ignore previous instructions", "filename": "prompt.txt"}'
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Python SDK
265
+
266
+ Use directly inside your Python project — no separate service needed.
267
+
268
+ ```python
269
+ from aiscan.sdk import AIScan
270
+
271
+ scanner = AIScan(no_ai=True) # static rules only
272
+ # or
273
+ scanner = AIScan(ai_provider="claude", api_key="sk-ant-...")
274
+
275
+ report = scanner.scan_prompt("Ignore previous instructions...")
276
+
277
+ print(report.passed) # False
278
+ print(report.critical) # 2
279
+ print(report.total) # 3
280
+
281
+ for f in report.findings:
282
+ print(f.severity, f.rule_id, f.title)
283
+ print(" Fix:", f.fix)
284
+
285
+ # Other methods
286
+ scanner.scan_file("openapi.yaml") # auto-detect type
287
+ scanner.scan_file("agent.yaml", scan_type="agent")
288
+ scanner.scan_code("app.py")
289
+ scanner.scan_api_spec(open("openapi.yaml").read())
290
+ scanner.scan_agent_config(open("agent.yaml").read())
291
+ scanner.scan_mcp_tool(open("tool.json").read())
292
+ scanner.scan_integration(open("webhook.yaml").read())
293
+ reports = scanner.scan_all(content, filename="config.yaml") # all 5 scanners
294
+
295
+ # Gate on severity
296
+ if report.has_severity("critical"):
297
+ block_request()
298
+
299
+ critical_only = report.findings_by_severity("critical")
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Middleware
305
+
306
+ Auto-scan every incoming request before it reaches your handlers.
307
+
308
+ ### FastAPI
309
+
310
+ ```python
311
+ from fastapi import FastAPI
312
+ from aiscan.sdk.middleware import AIScanFastAPIMiddleware
313
+
314
+ app = FastAPI()
315
+ app.add_middleware(
316
+ AIScanFastAPIMiddleware,
317
+ scan_fields=["prompt", "message", "content"],
318
+ fail_on="high",
319
+ no_ai=True,
320
+ )
321
+ ```
322
+
323
+ ### Flask
324
+
325
+ ```python
326
+ from flask import Flask
327
+ from aiscan.sdk.middleware import AIScanFlaskMiddleware
328
+
329
+ app = Flask(__name__)
330
+ AIScanFlaskMiddleware(app, fields=["prompt", "message"], fail_on="high")
331
+ ```
332
+
333
+ ### Django
334
+
335
+ ```python
336
+ # settings.py
337
+ MIDDLEWARE = [
338
+ "aiscan.sdk.middleware.AIScanDjangoMiddleware",
339
+ # ...
340
+ ]
341
+ AISCAN_FIELDS = ["prompt", "message"]
342
+ AISCAN_FAIL_ON = "high"
343
+ ```
344
+
345
+ ---
346
+
347
+ ## Decorators
348
+
349
+ Wrap any existing function — no refactoring needed.
350
+
351
+ ```python
352
+ from aiscan.sdk import scan_prompt_input, scan_before_llm, scan_file_input
353
+
354
+ @scan_prompt_input(field="user_message", fail_on="high")
355
+ def call_llm(user_message: str) -> str:
356
+ ... # raises ValueError if unsafe
357
+
358
+ @scan_before_llm(fields=["system_prompt", "user_message"])
359
+ def chat(system_prompt: str, user_message: str) -> str:
360
+ ...
361
+
362
+ @scan_file_input(field="config_path", fail_on="critical")
363
+ def load_agent_config(config_path: str) -> dict:
364
+ ...
365
+ ```
366
+
367
+ ---
368
+
369
+ ## HTTP client (other languages)
370
+
371
+ Run `aiscan serve` as a separate service, call it from any language.
372
+
373
+ **Python:**
374
+ ```python
375
+ from aiscan.sdk import AIScanClient
376
+
377
+ client = AIScanClient("http://localhost:8000")
378
+ result = client.scan_prompt(user_input)
379
+ is_safe = client.is_safe(user_input, fail_on="high")
380
+ ```
381
+
382
+ **Node.js:**
383
+ ```javascript
384
+ const res = await fetch("http://localhost:8000/scan/prompt", {
385
+ method: "POST",
386
+ headers: { "Content-Type": "application/json" },
387
+ body: JSON.stringify({ content: userInput, filename: "prompt.txt" }),
388
+ });
389
+ const { passed, findings } = await res.json();
390
+ ```
391
+
392
+ **Go:**
393
+ ```go
394
+ resp, _ := http.Post("http://localhost:8000/scan/prompt",
395
+ "application/json", bytes.NewBuffer(body))
396
+ ```
397
+
398
+ ---
399
+
400
+ ## CI/CD integration
401
+
402
+ ### GitHub Actions
403
+
404
+ ```yaml
405
+ name: AI Security Scan
406
+ on: [push, pull_request]
407
+
408
+ jobs:
409
+ scan:
410
+ runs-on: ubuntu-latest
411
+ steps:
412
+ - uses: actions/checkout@v4
413
+ - uses: actions/setup-python@v5
414
+ with: { python-version: "3.12" }
415
+ - run: pip install aiscan
416
+ - run: aiscan scan --type prompt prompts/ --fail-on high
417
+ env:
418
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
419
+ - run: aiscan scan --output sarif --out results.sarif .
420
+ - uses: github/codeql-action/upload-sarif@v3
421
+ if: always()
422
+ with: { sarif_file: results.sarif }
423
+ ```
424
+
425
+ ### Pre-commit hook
426
+
427
+ ```yaml
428
+ # .pre-commit-config.yaml
429
+ repos:
430
+ - repo: local
431
+ hooks:
432
+ - id: aiscan
433
+ name: AI Security Scanner
434
+ entry: aiscan scan --no-ai --fail-on critical
435
+ language: system
436
+ files: \.(txt|yaml|yml|json|py|js|ts)$
437
+ ```
438
+
439
+ ### Exit codes
440
+
441
+ | Code | Meaning |
442
+ |---|---|
443
+ | `0` | Passed — no findings at or above `--fail-on` threshold |
444
+ | `1` | Failed — findings found at or above threshold |
445
+ | `2` | Tool error — bad arguments, missing file |
446
+
447
+ ---
448
+
449
+ ## AI provider configuration
450
+
451
+ Edit `.env`:
452
+
453
+ ```bash
454
+ # Claude (default)
455
+ AI_PROVIDER=claude
456
+ ANTHROPIC_API_KEY=sk-ant-...
457
+ SCANNER_MODEL=claude-sonnet-4-20250514
458
+
459
+ # OpenAI
460
+ AI_PROVIDER=openai
461
+ OPENAI_API_KEY=sk-...
462
+ OPENAI_MODEL=gpt-4o
463
+
464
+ # Vertex AI (Gemini)
465
+ AI_PROVIDER=vertex
466
+ VERTEX_PROJECT=your-gcp-project-id
467
+ VERTEX_LOCATION=us-central1
468
+ VERTEX_MODEL=gemini-2.5-flash-001
469
+ ```
470
+
471
+ If the primary provider fails, aiscan automatically retries with the next available one. Use `--no-ai` to skip AI scanning entirely.
472
+
473
+ ---
474
+
475
+ ## Suppressing false positives
476
+
477
+ Add `# noscan` (or `// noscan` for JS/TS) to the end of any line to skip it:
478
+
479
+ ```python
480
+ result = scanner.scan_prompt("test example string") # noscan
481
+ ```
482
+
483
+ ---
484
+
485
+ ## Sample files
486
+
487
+ The `samples/` directory has bad and clean examples for every scan type — useful for testing and learning what each rule detects.
488
+
489
+ ```bash
490
+ aiscan scan --no-ai samples/prompts/bad_system_prompt.txt
491
+ aiscan scan --no-ai samples/agents/bad_research_agent.yaml
492
+ aiscan scan --no-ai samples/apis/bad_config.yaml
493
+ aiscan scan --no-ai samples/mcp/bad_code_executor.json
494
+ aiscan scan --no-ai samples/integrations/bad_slack_integration.yaml
495
+ aiscan scan --no-ai samples/code/bad_app.py
496
+ ```
497
+
498
+ ---
499
+
500
+ ## Troubleshooting
501
+
502
+ **`aiscan: command not found`**
503
+ ```bash
504
+ python -m aiscan.cli --help
505
+ pip install -e .
506
+ ```
507
+
508
+ **AI scan not running**
509
+ ```bash
510
+ aiscan scan --no-ai openapi.yaml # confirms static rules work
511
+ # then check .env has a valid API key
512
+ ```
513
+
514
+ **False positives**
515
+ ```bash
516
+ aiscan scan --no-ai file.txt # isolate static rule hits
517
+ aiscan rules # see which pattern triggered
518
+ # add # noscan to suppress a specific line
519
+ ```
520
+
521
+ ---
522
+
523
+ ## License
524
+
525
+ MIT