cisco-ai-skill-scanner 1.0.0__py3-none-any.whl → 1.0.2__py3-none-any.whl
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.
- {cisco_ai_skill_scanner-1.0.0.dist-info → cisco_ai_skill_scanner-1.0.2.dist-info}/METADATA +28 -13
- cisco_ai_skill_scanner-1.0.2.dist-info/RECORD +102 -0
- cisco_ai_skill_scanner-1.0.2.dist-info/entry_points.txt +4 -0
- {skillanalyzer → skill_scanner}/__init__.py +8 -4
- {skillanalyzer → skill_scanner}/_version.py +2 -2
- {skillanalyzer → skill_scanner}/api/__init__.py +1 -1
- {skillanalyzer → skill_scanner}/api/api.py +4 -4
- {skillanalyzer → skill_scanner}/api/api_cli.py +8 -8
- {skillanalyzer → skill_scanner}/api/api_server.py +7 -7
- {skillanalyzer → skill_scanner}/api/router.py +3 -3
- {skillanalyzer → skill_scanner}/cli/__init__.py +1 -1
- {skillanalyzer → skill_scanner}/cli/cli.py +71 -13
- {skillanalyzer → skill_scanner}/config/__init__.py +3 -3
- {skillanalyzer → skill_scanner}/config/config.py +2 -2
- {skillanalyzer → skill_scanner}/config/config_parser.py +9 -9
- {skillanalyzer → skill_scanner}/config/constants.py +2 -2
- skill_scanner/config/yara_modes.py +314 -0
- {skillanalyzer → skill_scanner}/core/__init__.py +1 -1
- {skillanalyzer → skill_scanner}/core/analyzers/__init__.py +3 -3
- {skillanalyzer → skill_scanner}/core/analyzers/aidefense_analyzer.py +3 -3
- {skillanalyzer → skill_scanner}/core/analyzers/behavioral/__init__.py +1 -1
- {skillanalyzer → skill_scanner}/core/analyzers/behavioral/alignment/alignment_llm_client.py +1 -1
- {skillanalyzer → skill_scanner}/core/analyzers/behavioral/alignment/alignment_prompt_builder.py +2 -2
- {skillanalyzer → skill_scanner}/core/analyzers/behavioral_analyzer.py +1 -1
- skillanalyzer/core/analyzers/cross_skill_analyzer.py → skill_scanner/core/analyzers/cross_skill_scanner.py +5 -5
- {skillanalyzer → skill_scanner}/core/analyzers/llm_analyzer.py +4 -4
- {skillanalyzer → skill_scanner}/core/analyzers/llm_prompt_builder.py +2 -2
- {skillanalyzer → skill_scanner}/core/analyzers/meta_analyzer.py +52 -20
- {skillanalyzer → skill_scanner}/core/analyzers/static.py +185 -35
- {skillanalyzer → skill_scanner}/core/analyzers/trigger_analyzer.py +2 -2
- {skillanalyzer → skill_scanner}/core/exceptions.py +10 -10
- {skillanalyzer → skill_scanner}/core/loader.py +4 -4
- {skillanalyzer → skill_scanner}/core/models.py +7 -6
- {skillanalyzer → skill_scanner}/core/reporters/markdown_reporter.py +11 -5
- {skillanalyzer → skill_scanner}/core/reporters/sarif_reporter.py +2 -2
- {skillanalyzer → skill_scanner}/core/reporters/table_reporter.py +2 -2
- {skillanalyzer → skill_scanner}/core/rules/yara_scanner.py +1 -1
- {skillanalyzer → skill_scanner}/core/scanner.py +2 -2
- {skillanalyzer → skill_scanner}/core/static_analysis/context_extractor.py +88 -14
- {skillanalyzer → skill_scanner}/core/static_analysis/dataflow/__init__.py +1 -1
- {skillanalyzer → skill_scanner}/core/static_analysis/interprocedural/call_graph_analyzer.py +2 -2
- {skillanalyzer → skill_scanner}/core/static_analysis/parser/python_parser.py +5 -5
- {skillanalyzer → skill_scanner}/data/__init__.py +1 -1
- {skillanalyzer → skill_scanner}/data/prompts/boilerplate_protection_rule_prompt.md +5 -5
- {skillanalyzer → skill_scanner}/data/prompts/code_alignment_threat_analysis_prompt.md +128 -53
- {skillanalyzer → skill_scanner}/data/prompts/llm_response_schema.json +3 -3
- {skillanalyzer → skill_scanner}/data/prompts/skill_meta_analysis_prompt.md +16 -15
- {skillanalyzer → skill_scanner}/data/prompts/skill_threat_analysis_prompt.md +53 -17
- {skillanalyzer → skill_scanner}/data/prompts/unified_response_schema.md +1 -1
- {skillanalyzer → skill_scanner}/data/rules/signatures.yaml +143 -37
- skill_scanner/data/yara_rules/autonomy_abuse_generic.yara +66 -0
- skillanalyzer/data/yara_rules/skill_discovery_abuse.yara → skill_scanner/data/yara_rules/capability_inflation_generic.yara +7 -4
- skill_scanner/data/yara_rules/code_execution_generic.yara +76 -0
- skillanalyzer/data/yara_rules/coercive_injection.yara → skill_scanner/data/yara_rules/coercive_injection_generic.yara +2 -2
- skill_scanner/data/yara_rules/command_injection_generic.yara +77 -0
- skillanalyzer/data/yara_rules/credential_harvesting.yara → skill_scanner/data/yara_rules/credential_harvesting_generic.yara +25 -4
- skillanalyzer/data/yara_rules/transitive_trust_abuse.yara → skill_scanner/data/yara_rules/indirect_prompt_injection_generic.yara +8 -5
- skillanalyzer/data/yara_rules/prompt_injection.yara → skill_scanner/data/yara_rules/prompt_injection_generic.yara +2 -2
- skillanalyzer/data/yara_rules/unicode_steganography.yara → skill_scanner/data/yara_rules/prompt_injection_unicode_steganography.yara +23 -17
- skill_scanner/data/yara_rules/script_injection_generic.yara +82 -0
- skillanalyzer/data/yara_rules/sql_injection.yara → skill_scanner/data/yara_rules/sql_injection_generic.yara +22 -8
- skill_scanner/data/yara_rules/system_manipulation_generic.yara +79 -0
- skill_scanner/data/yara_rules/tool_chaining_abuse_generic.yara +72 -0
- {skillanalyzer → skill_scanner}/hooks/__init__.py +1 -1
- {skillanalyzer → skill_scanner}/hooks/pre_commit.py +16 -16
- {skillanalyzer → skill_scanner}/threats/__init__.py +25 -3
- skill_scanner/threats/cisco_ai_taxonomy.py +274 -0
- {skillanalyzer → skill_scanner}/threats/threats.py +28 -99
- {skillanalyzer → skill_scanner}/utils/__init__.py +1 -1
- {skillanalyzer → skill_scanner}/utils/command_utils.py +1 -1
- {skillanalyzer → skill_scanner}/utils/di_container.py +1 -1
- {skillanalyzer → skill_scanner}/utils/logging_config.py +7 -7
- cisco_ai_skill_scanner-1.0.0.dist-info/RECORD +0 -100
- cisco_ai_skill_scanner-1.0.0.dist-info/entry_points.txt +0 -4
- skillanalyzer/data/yara_rules/autonomy_abuse.yara +0 -66
- skillanalyzer/data/yara_rules/code_execution.yara +0 -61
- skillanalyzer/data/yara_rules/command_injection.yara +0 -54
- skillanalyzer/data/yara_rules/script_injection.yara +0 -83
- skillanalyzer/data/yara_rules/system_manipulation.yara +0 -65
- skillanalyzer/data/yara_rules/tool_chaining_abuse.yara +0 -60
- {cisco_ai_skill_scanner-1.0.0.dist-info → cisco_ai_skill_scanner-1.0.2.dist-info}/WHEEL +0 -0
- {cisco_ai_skill_scanner-1.0.0.dist-info → cisco_ai_skill_scanner-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/base.py +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/behavioral/alignment/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/behavioral/alignment/alignment_orchestrator.py +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/behavioral/alignment/alignment_response_validator.py +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/behavioral/alignment/threat_vulnerability_classifier.py +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/llm_provider_config.py +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/llm_request_handler.py +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/llm_response_parser.py +0 -0
- {skillanalyzer → skill_scanner}/core/analyzers/virustotal_analyzer.py +0 -0
- {skillanalyzer → skill_scanner}/core/reporters/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/reporters/json_reporter.py +0 -0
- {skillanalyzer → skill_scanner}/core/rules/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/rules/patterns.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/cfg/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/cfg/builder.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/dataflow/forward_analysis.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/interprocedural/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/interprocedural/cross_file_analyzer.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/parser/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/semantic/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/semantic/name_resolver.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/semantic/type_analyzer.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/taint/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/taint/tracker.py +0 -0
- {skillanalyzer → skill_scanner}/core/static_analysis/types/__init__.py +0 -0
- {skillanalyzer → skill_scanner}/utils/file_utils.py +0 -0
- {skillanalyzer → skill_scanner}/utils/logging_utils.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cisco-ai-skill-scanner
|
|
3
|
-
Version: 1.0.
|
|
4
|
-
Summary: Security scanner for
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Security scanner for Agent Skills packages - Detects prompt injection, data exfiltration, and malicious code
|
|
5
5
|
Project-URL: Homepage, https://github.com/cisco-ai-defense/skill-scanner
|
|
6
6
|
Project-URL: Documentation, https://github.com/cisco-ai-defense/skill-scanner#readme
|
|
7
7
|
Project-URL: Repository, https://github.com/cisco-ai-defense/skill-scanner
|
|
@@ -68,14 +68,14 @@ Description-Content-Type: text/markdown
|
|
|
68
68
|
|
|
69
69
|
A security scanner for AI Agent Skills that detects prompt injection, data exfiltration, and malicious code patterns. Combines **pattern-based detection** (YAML + YARA), **LLM-as-a-judge**, and **behavioral dataflow analysis** for comprehensive threat detection.
|
|
70
70
|
|
|
71
|
-
Supports [
|
|
71
|
+
Supports [OpenAI Codex Skills](https://openai.github.io/codex/) and [Cursor Agent Skills](https://docs.cursor.com/context/rules) formats following the [Agent Skills specification](https://agentskills.io).
|
|
72
72
|
|
|
73
73
|
---
|
|
74
74
|
|
|
75
75
|
## Highlights
|
|
76
76
|
|
|
77
77
|
- **Multi-Engine Detection** - Static analysis, behavioral dataflow, LLM semantic analysis, and cloud-based scanning
|
|
78
|
-
- **False Positive Filtering** - Meta-analyzer
|
|
78
|
+
- **False Positive Filtering** - Meta-analyzer significantly reduces noise while preserving detection capability
|
|
79
79
|
- **CI/CD Ready** - SARIF output for GitHub Code Scanning, exit codes for build failures
|
|
80
80
|
- **Extensible** - Plugin architecture for custom analyzers
|
|
81
81
|
|
|
@@ -151,29 +151,41 @@ export AI_DEFENSE_API_KEY="your_aidefense_api_key"
|
|
|
151
151
|
|
|
152
152
|
```bash
|
|
153
153
|
# Scan a single skill (static analyzer only)
|
|
154
|
-
skill-
|
|
154
|
+
skill-scanner scan /path/to/skill
|
|
155
155
|
|
|
156
156
|
# Scan with behavioral analyzer (dataflow analysis)
|
|
157
|
-
skill-
|
|
157
|
+
skill-scanner scan /path/to/skill --use-behavioral
|
|
158
158
|
|
|
159
159
|
# Scan with all engines
|
|
160
|
-
skill-
|
|
160
|
+
skill-scanner scan /path/to/skill --use-behavioral --use-llm --use-aidefense
|
|
161
161
|
|
|
162
162
|
# Scan with meta-analyzer for false positive filtering
|
|
163
|
-
skill-
|
|
163
|
+
skill-scanner scan /path/to/skill --use-llm --enable-meta
|
|
164
164
|
|
|
165
165
|
# Scan multiple skills recursively
|
|
166
|
-
skill-
|
|
166
|
+
skill-scanner scan-all /path/to/skills --recursive --use-behavioral
|
|
167
167
|
|
|
168
168
|
# CI/CD: Fail build if threats found
|
|
169
|
-
skill-
|
|
169
|
+
skill-scanner scan-all ./skills --fail-on-findings --format sarif --output results.sarif
|
|
170
|
+
|
|
171
|
+
# Use custom YARA rules
|
|
172
|
+
skill-scanner scan /path/to/skill --custom-rules /path/to/my-rules/
|
|
173
|
+
|
|
174
|
+
# Disable specific noisy rules
|
|
175
|
+
skill-scanner scan /path/to/skill --disable-rule YARA_script_injection --disable-rule MANIFEST_MISSING_LICENSE
|
|
176
|
+
|
|
177
|
+
# Strict mode (more findings, higher FP rate)
|
|
178
|
+
skill-scanner scan /path/to/skill --yara-mode strict
|
|
179
|
+
|
|
180
|
+
# Permissive mode (fewer findings, may miss some threats)
|
|
181
|
+
skill-scanner scan /path/to/skill --yara-mode permissive
|
|
170
182
|
```
|
|
171
183
|
|
|
172
184
|
### Python SDK
|
|
173
185
|
|
|
174
186
|
```python
|
|
175
|
-
from
|
|
176
|
-
from
|
|
187
|
+
from skill_scanner import SkillScanner
|
|
188
|
+
from skill_scanner.core.analyzers import StaticAnalyzer, BehavioralAnalyzer
|
|
177
189
|
|
|
178
190
|
# Create scanner with analyzers
|
|
179
191
|
scanner = SkillScanner(analyzers=[
|
|
@@ -215,13 +227,16 @@ print(f"Findings: {len(result.findings)}")
|
|
|
215
227
|
| `--format` | Output: `summary`, `json`, `markdown`, `table`, `sarif` |
|
|
216
228
|
| `--output PATH` | Save report to file |
|
|
217
229
|
| `--fail-on-findings` | Exit with error if HIGH/CRITICAL found |
|
|
230
|
+
| `--yara-mode` | Detection mode: `strict`, `balanced` (default), `permissive` |
|
|
231
|
+
| `--custom-rules PATH` | Use custom YARA rules from directory |
|
|
232
|
+
| `--disable-rule RULE` | Disable specific rule (can repeat) |
|
|
218
233
|
|
|
219
234
|
---
|
|
220
235
|
|
|
221
236
|
## Example Output
|
|
222
237
|
|
|
223
238
|
```
|
|
224
|
-
$ skill-
|
|
239
|
+
$ skill-scanner scan ./my-skill --use-behavioral
|
|
225
240
|
|
|
226
241
|
============================================================
|
|
227
242
|
Skill: my-skill
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
skill_scanner/__init__.py,sha256=QuGYhgc529C5Cjtk3Th5t7-Qkx9kxOv6E2GK6soGZQw,1383
|
|
2
|
+
skill_scanner/_version.py,sha256=ZTgKq8LPNy3l9uR2ke-VtLhvvl5l71frQ9wO76n1L5k,704
|
|
3
|
+
skill_scanner/api/__init__.py,sha256=vhuGqXgBx70izjHQOa-cWm3cbHlKhkpEiRjpusQ49vo,746
|
|
4
|
+
skill_scanner/api/api.py,sha256=5fFYh1e1JE06pNtZw-7zMcQMc791ubNlck0VjWzskq8,1027
|
|
5
|
+
skill_scanner/api/api_cli.py,sha256=NcBQyhW1YtFi97A7btNMyC3wtBxk07dRsZdOhFNKt-Q,2378
|
|
6
|
+
skill_scanner/api/api_server.py,sha256=liHVVSOaLoYOYBGyg3DWKJSVPMZF7L26uPvLKrtg9R4,21112
|
|
7
|
+
skill_scanner/api/router.py,sha256=3u5qPWO48iF09oIm-3oxYkqqO4hT50jCaNQTr2TBfYc,17411
|
|
8
|
+
skill_scanner/cli/__init__.py,sha256=UOFAWN8z8nMviFLHiFrtlcHn4eGbbRZc4B2q8yWlTno,755
|
|
9
|
+
skill_scanner/cli/cli.py,sha256=AFFJbsZ7GnA4bYUbivgqbjTWlWiwWU4oMGy96WBybkE,37747
|
|
10
|
+
skill_scanner/config/__init__.py,sha256=S0hMvyq3Vi0wWET74XmbPQmBTBkLXtqFca5PcTYosUM,837
|
|
11
|
+
skill_scanner/config/config.py,sha256=SvK9lvTNjpygc80pamDaGDtOhh99qGBG3EJiFKfEVzc,4698
|
|
12
|
+
skill_scanner/config/config_parser.py,sha256=kGPawiniy35fyUoJvnwRsJsgtIiAjSXHhE3joUcZtn8,3772
|
|
13
|
+
skill_scanner/config/constants.py,sha256=re2KkOtvSnxSJgkamdIU0fjdQ-fUSHX1eQSEfKDXjTA,2512
|
|
14
|
+
skill_scanner/config/yara_modes.py,sha256=1jgdVdLWC_oSJPuk4BCeUZU9lm9X7NwiDjTXeSCeGpw,11425
|
|
15
|
+
skill_scanner/core/__init__.py,sha256=fC3n7lJs_G8CFz2Vg1gfGFe6b0pBiCUs7MRW4kCM1CY,822
|
|
16
|
+
skill_scanner/core/exceptions.py,sha256=F4k2RDXIxrrnNsAsHn7wR277i2dNOXdK-NK0r-m3nF0,2007
|
|
17
|
+
skill_scanner/core/loader.py,sha256=cIU7e5MZHxryr-7UiGwI76eM0Zbm-LrmRGI0mP1_17A,13541
|
|
18
|
+
skill_scanner/core/models.py,sha256=Zkp_CUHfXpWLSY_ceXLqazdIIqMJqaicWzxIQW0HgSk,10591
|
|
19
|
+
skill_scanner/core/scanner.py,sha256=zAtM3Hbs_NNbYV7iq-9W2BURO-H23uRJ-E14S2h_wek,14830
|
|
20
|
+
skill_scanner/core/analyzers/__init__.py,sha256=tctB8Q30gA5V4pdR5yoSpxyIKJZkFTJwowUq6UwddQo,2132
|
|
21
|
+
skill_scanner/core/analyzers/aidefense_analyzer.py,sha256=ws61J3KJsz1DiuucBPCdsWN8ACI_iurtDQzWtFqfCA8,36468
|
|
22
|
+
skill_scanner/core/analyzers/base.py,sha256=4BN6dHLn2Q9hQMLAJTSJXsl6tZgfCqqBxZO9icuu70Q,1374
|
|
23
|
+
skill_scanner/core/analyzers/behavioral_analyzer.py,sha256=dvdTdwUKHqnmEa1nsChcdlJ0V_WvcZrGyHX5uYe0clI,19076
|
|
24
|
+
skill_scanner/core/analyzers/cross_skill_scanner.py,sha256=MTedSXhLagZeXEtvkPV8m_48GqoHMWkh9rR9FR9puLQ,18934
|
|
25
|
+
skill_scanner/core/analyzers/llm_analyzer.py,sha256=biH2g_hych5dAecQL7bKi3GsW9P_nPGerRiEeoOLr2I,17963
|
|
26
|
+
skill_scanner/core/analyzers/llm_prompt_builder.py,sha256=28OCgMUE0T-A6GkF5sUY0qPFvaKC1jhB6jPjVPbePsw,10160
|
|
27
|
+
skill_scanner/core/analyzers/llm_provider_config.py,sha256=pbVx7N9OCohjIWjENMq-kiy6_svTn4IYvQfPxlR0M_Y,8488
|
|
28
|
+
skill_scanner/core/analyzers/llm_request_handler.py,sha256=nz_gjnDTr0dT2GbfQMqKR6-n63x38AcB5G4UnPHLY9s,11679
|
|
29
|
+
skill_scanner/core/analyzers/llm_response_parser.py,sha256=wO5ovd4se-KqIPwdZX-r0_tozaJEDUx7Q7yajKntPwk,2682
|
|
30
|
+
skill_scanner/core/analyzers/meta_analyzer.py,sha256=9nFZFinooTuKaAO-CM_HTJxopw2GPxnn5ZXvJ2ZORCU,35017
|
|
31
|
+
skill_scanner/core/analyzers/static.py,sha256=5mDPHbiD5jHxjGenfX68owXY6DqEkqaKRADkLpTQn48,51979
|
|
32
|
+
skill_scanner/core/analyzers/trigger_analyzer.py,sha256=bmJjaGdSqsAyvOIehHbMjLrDWysd7YV9J9TXgMvTEe0,12268
|
|
33
|
+
skill_scanner/core/analyzers/virustotal_analyzer.py,sha256=V7nG-fR2GhfdZhh8JVNvM6gOqRyUGsuxHN1yNRvmw6M,15988
|
|
34
|
+
skill_scanner/core/analyzers/behavioral/__init__.py,sha256=aTuJyqDbylHE2Ags_LaYLbbOkkJxkTDP--VBU-KMPgs,1069
|
|
35
|
+
skill_scanner/core/analyzers/behavioral/alignment/__init__.py,sha256=nB2KWYnDu6I4yGiaewEyySzG4w96hElXiQBqJFfGmP4,1832
|
|
36
|
+
skill_scanner/core/analyzers/behavioral/alignment/alignment_llm_client.py,sha256=mRocjOvf8jM2UQ-_TzcHRQDVkEeoPXu87GjwKiuZ2Yw,8645
|
|
37
|
+
skill_scanner/core/analyzers/behavioral/alignment/alignment_orchestrator.py,sha256=zfkjFz-DDwUEOGDBpJ8cAZi5bH-VP_d_1bJTF1z0Si4,9478
|
|
38
|
+
skill_scanner/core/analyzers/behavioral/alignment/alignment_prompt_builder.py,sha256=oAGvbIBmCP6APYwYXKsVyh0jWBgaiM5N6Bo5YoHbJT8,18041
|
|
39
|
+
skill_scanner/core/analyzers/behavioral/alignment/alignment_response_validator.py,sha256=lu0gPPRbJkZJlkguqwUeSVl43HpMFypICXH_4s8Zjbo,4556
|
|
40
|
+
skill_scanner/core/analyzers/behavioral/alignment/threat_vulnerability_classifier.py,sha256=DCXnbs9Fa2ajFT0We4sOo6nxIk7O_Pc0z01fGMDHsRg,7227
|
|
41
|
+
skill_scanner/core/reporters/__init__.py,sha256=XCqeM_kiS1uvcwymDreueQ2KOzMhG5_4vQgxzReJS4w,943
|
|
42
|
+
skill_scanner/core/reporters/json_reporter.py,sha256=JLlPTbs8ncMJHAXZk7iBWCHdL5Qn2PqHOQldHeH2ZGE,1798
|
|
43
|
+
skill_scanner/core/reporters/markdown_reporter.py,sha256=khOEHC2mshwu97EF3KW2f00l-VvHpq0_HkVzCsWAKm8,8064
|
|
44
|
+
skill_scanner/core/reporters/sarif_reporter.py,sha256=8BUUerHX-gpE-5HYAipfCLH3GdlVuul43ZItHDAB7Bw,8289
|
|
45
|
+
skill_scanner/core/reporters/table_reporter.py,sha256=sotaDM2VzaX4vCR-OrF3GyIX_yv7wWhzS_doyc1I1XE,7044
|
|
46
|
+
skill_scanner/core/rules/__init__.py,sha256=zGlTBVjihqxgg0BKmhdGkyeCzSvRjVEASjBh-M0sn_8,680
|
|
47
|
+
skill_scanner/core/rules/patterns.py,sha256=OuJ6mPlQVy9R8g1Pn9ozWIC8iWfDEuQamdDW5Uu8200,5833
|
|
48
|
+
skill_scanner/core/rules/yara_scanner.py,sha256=U-qYrb92n3664cTt7ynRTMVGGsxhfrSU0OOYV-BnxKc,5326
|
|
49
|
+
skill_scanner/core/static_analysis/__init__.py,sha256=meZnZQj7ChgHek6fIrfd-YInolXCqI37HTUTlQWEm7w,930
|
|
50
|
+
skill_scanner/core/static_analysis/context_extractor.py,sha256=v3UUugDuC4WHGnHc2gcHLa6awlVpQZIBhCmCxFsuBes,32264
|
|
51
|
+
skill_scanner/core/static_analysis/cfg/__init__.py,sha256=jkvx12ZGddbRVu_0b04Bamr7JX084yD6BLxgOUEHT1w,816
|
|
52
|
+
skill_scanner/core/static_analysis/cfg/builder.py,sha256=Tm1GZ56rfOoNx-3WLmn2MNov2KzPKN-QZgJbBG-9D2c,14932
|
|
53
|
+
skill_scanner/core/static_analysis/dataflow/__init__.py,sha256=eVdTh0JOvQvtKG96gqs_1VvIU0_sRNkV6sXZz6X9o7I,833
|
|
54
|
+
skill_scanner/core/static_analysis/dataflow/forward_analysis.py,sha256=haHWJVz-SZxZpZoEwAsNOum-67ldppe_YBRMZOSJqz0,30747
|
|
55
|
+
skill_scanner/core/static_analysis/interprocedural/__init__.py,sha256=dFIglo65HpWMJ80ejB4tjv54MaNeSymQ5eowD5QGZic,798
|
|
56
|
+
skill_scanner/core/static_analysis/interprocedural/call_graph_analyzer.py,sha256=3azYWJ8A5-I39gc5zK4Iz6g0AAUX_uos4CNh1sVQNQA,14060
|
|
57
|
+
skill_scanner/core/static_analysis/interprocedural/cross_file_analyzer.py,sha256=neP8pdyGhCUHJQmmTXfm0X_CFHlTHh7e3RU7HVJ0UVY,7472
|
|
58
|
+
skill_scanner/core/static_analysis/parser/__init__.py,sha256=AXCg1HHVzyjswGJl4TNFhzwMKxgin8JY2EK00RVv9_Y,769
|
|
59
|
+
skill_scanner/core/static_analysis/parser/python_parser.py,sha256=Imlv4PO6XZKQpdCRZ6jV5uBAySuBN6XnHAqH4LEvvGE,13773
|
|
60
|
+
skill_scanner/core/static_analysis/semantic/__init__.py,sha256=7HS7lJ4APpyfWLTUQ_24aJkrLX2MQTcc4erYFtLKm3o,877
|
|
61
|
+
skill_scanner/core/static_analysis/semantic/name_resolver.py,sha256=TEJQkEaTvkL7dnAZwNbcLALPVw85Qc3FS5jfr4CYEsQ,6218
|
|
62
|
+
skill_scanner/core/static_analysis/semantic/type_analyzer.py,sha256=NXEOZO8-vYZ97SQJ5Gu_YLWFDMDhtvtuixVwYGarmDM,5942
|
|
63
|
+
skill_scanner/core/static_analysis/taint/__init__.py,sha256=71JejlK110K2r3LXNIJOLGCZ7I5Q7cEn8XvfCCoEexA,809
|
|
64
|
+
skill_scanner/core/static_analysis/taint/tracker.py,sha256=1WExA8NAV62X5Az64grI41LkkyMNQ7kFS8Mzf6Id1NI,7182
|
|
65
|
+
skill_scanner/core/static_analysis/types/__init__.py,sha256=XluM6BlZ8ECfdAD-231ONJn13UeDdAGmirPAVc0zePk,937
|
|
66
|
+
skill_scanner/data/__init__.py,sha256=eeZz0MhPMEV-PAx8Eqpbb4ey6EHbXT5g8j-DC4427A4,969
|
|
67
|
+
skill_scanner/data/prompts/boilerplate_protection_rule_prompt.md,sha256=DNXYx13Mcbn2q9hw4msTDDbq_VcYCiVkqBZVFSNfzOg,1471
|
|
68
|
+
skill_scanner/data/prompts/code_alignment_threat_analysis_prompt.md,sha256=j5U3YVKMM5HOndCl3cc_4CA190zBj9Z9tP8rLqz-M7c,25686
|
|
69
|
+
skill_scanner/data/prompts/llm_response_schema.json,sha256=xIxrWgPMWqL130AuV0-QkQIHAfQTK-NeJVPrsSIzL2s,3076
|
|
70
|
+
skill_scanner/data/prompts/skill_meta_analysis_prompt.md,sha256=_3jbZVKOiJx47V2d6rQ4sc4MpKFC9oN_7-c7_LxPUs8,14179
|
|
71
|
+
skill_scanner/data/prompts/skill_threat_analysis_prompt.md,sha256=ycE_a43c7qhUT6HwbP8zoKwTTNx3Nx4FyPuxicJ6r5I,11813
|
|
72
|
+
skill_scanner/data/prompts/unified_response_schema.md,sha256=-f1EDpKzxjMMFFxXlakS3rORyLtD1_2XiuNwnty1nQs,3571
|
|
73
|
+
skill_scanner/data/rules/signatures.yaml,sha256=GY41ZCvc2HIInwSnIYKLyHTK36J2hdOFyT-wRUhB3GU,19451
|
|
74
|
+
skill_scanner/data/yara_rules/autonomy_abuse_generic.yara,sha256=epgJRIj_qOYSZSsOQi4Tnv99T8rqbltNbZhECczRQXw,3097
|
|
75
|
+
skill_scanner/data/yara_rules/capability_inflation_generic.yara,sha256=RkDaqDtkcLULxr1Vb0XQ-5Q1BMwErkYcKx-sH6u0f1I,2610
|
|
76
|
+
skill_scanner/data/yara_rules/code_execution_generic.yara,sha256=c5W7h5Vl4rLgAabL9As4IkmNSbf4aAbzIH4kiaSYce4,3057
|
|
77
|
+
skill_scanner/data/yara_rules/coercive_injection_generic.yara,sha256=LQcfpAuzY1zC9N_xT-qfi72fCJm7mY0C2l89eFdTMKE,5363
|
|
78
|
+
skill_scanner/data/yara_rules/command_injection_generic.yara,sha256=vl1a4yYXloJk4lMFHbCmj16l0Th9IRDHu4_zH168sFY,3318
|
|
79
|
+
skill_scanner/data/yara_rules/credential_harvesting_generic.yara,sha256=iwgBlMt85i3VOrDkBMfHvwtO6PhF1Igh6m3Uj3CBOEI,7192
|
|
80
|
+
skill_scanner/data/yara_rules/indirect_prompt_injection_generic.yara,sha256=AHGYsEu6pRbNkpsb_sGOKaYSzpIR809ixxjxxRjaWY0,2977
|
|
81
|
+
skill_scanner/data/yara_rules/prompt_injection_generic.yara,sha256=OJMKzA1D6QXEEoogMnIeGp6NT308N5OY78uWjJBoODI,2752
|
|
82
|
+
skill_scanner/data/yara_rules/prompt_injection_unicode_steganography.yara,sha256=yALtLuRpoCu9toc5Wk3Av_W4GiWDFmpVNYaF2k3IAyk,3048
|
|
83
|
+
skill_scanner/data/yara_rules/script_injection_generic.yara,sha256=C4k3okg0APx0s4qxwSJc0swhp9AfAsACggnl-LYIoJg,3513
|
|
84
|
+
skill_scanner/data/yara_rules/sql_injection_generic.yara,sha256=Eu3EhTgYFGaOTjujMjwsjvnPrBihnfvq_9URCwDYyME,4642
|
|
85
|
+
skill_scanner/data/yara_rules/system_manipulation_generic.yara,sha256=hY1XmpYoKD6Eywwa51lL1DUXjwV7h1WRXk4TWYWzbic,3136
|
|
86
|
+
skill_scanner/data/yara_rules/tool_chaining_abuse_generic.yara,sha256=-sLNCZePTzk49exbQAorTCqKu-1bWWRD7oI6i2mj7kk,2867
|
|
87
|
+
skill_scanner/hooks/__init__.py,sha256=W7_Xr71Edm6eHKz9_vZgpERbr0Wx2cyTxPn4YJaGg6o,739
|
|
88
|
+
skill_scanner/hooks/pre_commit.py,sha256=dtajQcyAlSaH15J1O9HHQ67xrGj2P6M2pHN6MZ0htwY,13207
|
|
89
|
+
skill_scanner/threats/__init__.py,sha256=TpqVYCcjQGGpcsTR_1iIvrTT55Sd1ed15sVfGVfZJwk,1320
|
|
90
|
+
skill_scanner/threats/cisco_ai_taxonomy.py,sha256=pXBPgwqfFgKN8Jax3aue66v306aETX6bOSgoRu-zUMg,12910
|
|
91
|
+
skill_scanner/threats/threats.py,sha256=7r0V0HJFWI7m-PMoZECnwK3ANKyTzTYM3bEUG2tgUH8,17981
|
|
92
|
+
skill_scanner/utils/__init__.py,sha256=mmzKMNaDQ3EtmD2zr_68gMatm4OETbVNtEXuVESxzJs,906
|
|
93
|
+
skill_scanner/utils/command_utils.py,sha256=74rojYVuVWpv-HVdW0qTIzq0ySPdpBuyNTdIQZDakUM,4291
|
|
94
|
+
skill_scanner/utils/di_container.py,sha256=O3aaQVKcu4t1YUXl9iCZxjSBXnvgddlTgmEp0De_g04,4585
|
|
95
|
+
skill_scanner/utils/file_utils.py,sha256=LT2xwrbqIWaYC-BYAL9zpF6a2xk6QNUVzItvGGJcBn8,2043
|
|
96
|
+
skill_scanner/utils/logging_config.py,sha256=8LJwRCVM-oED_6KRDvtjaL8cvEoR88seX1pDyILeQV4,2939
|
|
97
|
+
skill_scanner/utils/logging_utils.py,sha256=CLdOYmQdJejiLbcECTT2CbDU27PJ327AFMmeuVfCy94,1902
|
|
98
|
+
cisco_ai_skill_scanner-1.0.2.dist-info/METADATA,sha256=EzizoVjYbxLZk_xxnyv052t5bNdvd7APCYXzbDd-Xh8,9827
|
|
99
|
+
cisco_ai_skill_scanner-1.0.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
100
|
+
cisco_ai_skill_scanner-1.0.2.dist-info/entry_points.txt,sha256=Qpg94wQPc6kWF_KQ-jf2tL_wCJ3aJfZ4V4vsYz50GIw,175
|
|
101
|
+
cisco_ai_skill_scanner-1.0.2.dist-info/licenses/LICENSE,sha256=b4va5sK_CWxpeDnOO2MF0MKqsiwU-3YblMmWKnmuWZg,653
|
|
102
|
+
cisco_ai_skill_scanner-1.0.2.dist-info/RECORD,,
|
|
@@ -15,15 +15,19 @@
|
|
|
15
15
|
# SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
|
|
17
17
|
"""
|
|
18
|
-
|
|
18
|
+
Skill Scanner - Security scanner for agent skills packages.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
try:
|
|
22
|
+
from ._version import __version__
|
|
23
|
+
except ImportError:
|
|
24
|
+
__version__ = "0.0.0+unknown"
|
|
25
|
+
|
|
22
26
|
__author__ = "Cisco Systems, Inc."
|
|
23
27
|
|
|
24
28
|
# Core exports
|
|
25
29
|
from .config.config import Config
|
|
26
|
-
from .config.constants import
|
|
30
|
+
from .config.constants import SkillScannerConstants
|
|
27
31
|
from .core.loader import SkillLoader, load_skill
|
|
28
32
|
from .core.models import Finding, Report, ScanResult, Severity, Skill, ThreatCategory
|
|
29
33
|
from .core.scanner import SkillScanner, scan_directory, scan_skill
|
|
@@ -41,5 +45,5 @@ __all__ = [
|
|
|
41
45
|
"SkillLoader",
|
|
42
46
|
"load_skill",
|
|
43
47
|
"Config",
|
|
44
|
-
"
|
|
48
|
+
"SkillScannerConstants",
|
|
45
49
|
]
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 0,
|
|
31
|
+
__version__ = version = '1.0.2'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 0, 2)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
#
|
|
15
15
|
# SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
|
|
17
|
-
"""API module for Skill
|
|
17
|
+
"""API module for Skill Scanner.
|
|
18
18
|
|
|
19
|
-
This module provides a FastAPI application for scanning
|
|
19
|
+
This module provides a FastAPI application for scanning agent skills packages.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
from fastapi import FastAPI
|
|
@@ -24,8 +24,8 @@ from fastapi import FastAPI
|
|
|
24
24
|
from .router import router as api_router
|
|
25
25
|
|
|
26
26
|
app = FastAPI(
|
|
27
|
-
title="
|
|
28
|
-
description="Security scanning API for
|
|
27
|
+
title="Skill Scanner API",
|
|
28
|
+
description="Security scanning API for agent skills packages",
|
|
29
29
|
version="0.2.0",
|
|
30
30
|
docs_url="/docs",
|
|
31
31
|
redoc_url="/redoc",
|
|
@@ -25,25 +25,25 @@ import sys
|
|
|
25
25
|
def main():
|
|
26
26
|
"""Main entry point for API server CLI."""
|
|
27
27
|
parser = argparse.ArgumentParser(
|
|
28
|
-
description="
|
|
28
|
+
description="Skill Scanner API Server",
|
|
29
29
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
30
30
|
epilog="""
|
|
31
31
|
Examples:
|
|
32
32
|
# Start server on default port
|
|
33
|
-
skill-
|
|
33
|
+
skill-scanner-api
|
|
34
34
|
|
|
35
35
|
# Start on custom port
|
|
36
|
-
skill-
|
|
36
|
+
skill-scanner-api --port 8080
|
|
37
37
|
|
|
38
38
|
# Start with auto-reload for development
|
|
39
|
-
skill-
|
|
39
|
+
skill-scanner-api --reload
|
|
40
40
|
|
|
41
41
|
# Custom host and port
|
|
42
|
-
skill-
|
|
42
|
+
skill-scanner-api --host localhost --port 9000
|
|
43
43
|
""",
|
|
44
44
|
)
|
|
45
45
|
|
|
46
|
-
parser.add_argument("--host", default="
|
|
46
|
+
parser.add_argument("--host", default="localhost", help="Host to bind to (default: localhost)")
|
|
47
47
|
|
|
48
48
|
parser.add_argument("--port", type=int, default=8000, help="Port to bind to (default: 8000)")
|
|
49
49
|
|
|
@@ -58,14 +58,14 @@ Examples:
|
|
|
58
58
|
print("Install with: pip install fastapi uvicorn python-multipart", file=sys.stderr)
|
|
59
59
|
return 1
|
|
60
60
|
|
|
61
|
-
print("Starting
|
|
61
|
+
print("Starting Skill Scanner API Server...")
|
|
62
62
|
print(f"Server: http://{args.host}:{args.port}")
|
|
63
63
|
print(f"Docs: http://{args.host}:{args.port}/docs")
|
|
64
64
|
print(f"Health: http://{args.host}:{args.port}/health")
|
|
65
65
|
print()
|
|
66
66
|
|
|
67
67
|
try:
|
|
68
|
-
uvicorn.run("
|
|
68
|
+
uvicorn.run("skill_scanner.api.api:app", host=args.host, port=args.port, reload=args.reload)
|
|
69
69
|
except KeyboardInterrupt:
|
|
70
70
|
print("\nShutting down server...")
|
|
71
71
|
return 0
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
|
|
17
17
|
"""
|
|
18
|
-
REST API server for
|
|
18
|
+
REST API server for Skill Scanner.
|
|
19
19
|
|
|
20
20
|
Provides HTTP endpoints for skill scanning, similar to MCP Scanner's API server.
|
|
21
21
|
"""
|
|
@@ -126,8 +126,8 @@ class BatchScanRequest(BaseModel):
|
|
|
126
126
|
|
|
127
127
|
# Create FastAPI app
|
|
128
128
|
app = FastAPI(
|
|
129
|
-
title="
|
|
130
|
-
description="Security scanning API for
|
|
129
|
+
title="Skill Scanner API",
|
|
130
|
+
description="Security scanning API for agent skills packages",
|
|
131
131
|
version="0.2.0",
|
|
132
132
|
docs_url="/docs",
|
|
133
133
|
redoc_url="/redoc",
|
|
@@ -140,7 +140,7 @@ scan_results_cache = {}
|
|
|
140
140
|
@app.get("/", response_model=dict)
|
|
141
141
|
async def root():
|
|
142
142
|
"""Root endpoint."""
|
|
143
|
-
return {"service": "
|
|
143
|
+
return {"service": "Skill Scanner API", "version": "0.2.0", "docs": "/docs", "health": "/health"}
|
|
144
144
|
|
|
145
145
|
|
|
146
146
|
@app.get("/health", response_model=HealthResponse)
|
|
@@ -309,7 +309,7 @@ async def scan_uploaded_skill(
|
|
|
309
309
|
raise HTTPException(status_code=400, detail="File must be a ZIP archive")
|
|
310
310
|
|
|
311
311
|
# Create temporary directory
|
|
312
|
-
temp_dir = Path(tempfile.mkdtemp(prefix="
|
|
312
|
+
temp_dir = Path(tempfile.mkdtemp(prefix="skill_scanner_"))
|
|
313
313
|
|
|
314
314
|
try:
|
|
315
315
|
# Save uploaded file
|
|
@@ -616,7 +616,7 @@ async def list_analyzers():
|
|
|
616
616
|
|
|
617
617
|
|
|
618
618
|
# Entry point for running the server
|
|
619
|
-
def run_server(host: str = "
|
|
619
|
+
def run_server(host: str = "localhost", port: int = 8000, reload: bool = False):
|
|
620
620
|
"""
|
|
621
621
|
Run the API server.
|
|
622
622
|
|
|
@@ -627,7 +627,7 @@ def run_server(host: str = "0.0.0.0", port: int = 8000, reload: bool = False):
|
|
|
627
627
|
"""
|
|
628
628
|
import uvicorn
|
|
629
629
|
|
|
630
|
-
uvicorn.run("
|
|
630
|
+
uvicorn.run("skill_scanner.api.api_server:app", host=host, port=port, reload=reload)
|
|
631
631
|
|
|
632
632
|
|
|
633
633
|
if __name__ == "__main__":
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
#
|
|
15
15
|
# SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
|
|
17
|
-
"""API router for Skill
|
|
17
|
+
"""API router for Skill Scanner endpoints."""
|
|
18
18
|
|
|
19
19
|
import shutil
|
|
20
20
|
import tempfile
|
|
@@ -123,7 +123,7 @@ class BatchScanRequest(BaseModel):
|
|
|
123
123
|
@router.get("/", response_model=dict)
|
|
124
124
|
async def root():
|
|
125
125
|
"""Root endpoint."""
|
|
126
|
-
return {"service": "
|
|
126
|
+
return {"service": "Skill Scanner API", "version": "0.2.0", "docs": "/docs", "health": "/health"}
|
|
127
127
|
|
|
128
128
|
|
|
129
129
|
@router.get("/health", response_model=HealthResponse)
|
|
@@ -282,7 +282,7 @@ async def scan_uploaded_skill(
|
|
|
282
282
|
if not file.filename or not file.filename.endswith(".zip"):
|
|
283
283
|
raise HTTPException(status_code=400, detail="File must be a ZIP archive")
|
|
284
284
|
|
|
285
|
-
temp_dir = Path(tempfile.mkdtemp(prefix="
|
|
285
|
+
temp_dir = Path(tempfile.mkdtemp(prefix="skill_scanner_"))
|
|
286
286
|
|
|
287
287
|
try:
|
|
288
288
|
zip_path = temp_dir / file.filename
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
|
|
17
17
|
"""
|
|
18
|
-
Command-line interface for the
|
|
18
|
+
Command-line interface for the Skill Scanner.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
import argparse
|
|
@@ -62,8 +62,19 @@ def scan_command(args):
|
|
|
62
62
|
print(f"Error: Directory does not exist: {skill_dir}", file=sys.stderr)
|
|
63
63
|
return 1
|
|
64
64
|
|
|
65
|
+
# Get YARA mode and custom rules from args
|
|
66
|
+
yara_mode = getattr(args, "yara_mode", "balanced")
|
|
67
|
+
custom_rules_path = getattr(args, "custom_rules", None)
|
|
68
|
+
disabled_rules = set(getattr(args, "disabled_rules", None) or [])
|
|
69
|
+
|
|
65
70
|
# Create scanner with configured analyzers
|
|
66
|
-
analyzers = [
|
|
71
|
+
analyzers = [
|
|
72
|
+
StaticAnalyzer(
|
|
73
|
+
yara_mode=yara_mode,
|
|
74
|
+
custom_yara_rules_path=custom_rules_path,
|
|
75
|
+
disabled_rules=disabled_rules,
|
|
76
|
+
)
|
|
77
|
+
]
|
|
67
78
|
|
|
68
79
|
# Helper to print status messages - go to stderr when JSON output to avoid breaking parsing
|
|
69
80
|
is_json_output = getattr(args, "format", "summary") == "json"
|
|
@@ -273,8 +284,19 @@ def scan_all_command(args):
|
|
|
273
284
|
print(f"Error: Directory does not exist: {skills_dir}", file=sys.stderr)
|
|
274
285
|
return 1
|
|
275
286
|
|
|
287
|
+
# Get YARA mode and custom rules from args
|
|
288
|
+
yara_mode = getattr(args, "yara_mode", "balanced")
|
|
289
|
+
custom_rules_path = getattr(args, "custom_rules", None)
|
|
290
|
+
disabled_rules = set(getattr(args, "disabled_rules", None) or [])
|
|
291
|
+
|
|
276
292
|
# Create scanner with configured analyzers
|
|
277
|
-
analyzers = [
|
|
293
|
+
analyzers = [
|
|
294
|
+
StaticAnalyzer(
|
|
295
|
+
yara_mode=yara_mode,
|
|
296
|
+
custom_yara_rules_path=custom_rules_path,
|
|
297
|
+
disabled_rules=disabled_rules,
|
|
298
|
+
)
|
|
299
|
+
]
|
|
278
300
|
|
|
279
301
|
# Helper to print status messages - go to stderr when JSON output to avoid breaking parsing
|
|
280
302
|
is_json_output = getattr(args, "format", "summary") == "json"
|
|
@@ -623,7 +645,7 @@ def generate_multi_skill_summary(report) -> str:
|
|
|
623
645
|
"""Generate a simple summary for multiple skills."""
|
|
624
646
|
lines = []
|
|
625
647
|
lines.append("=" * 60)
|
|
626
|
-
lines.append("
|
|
648
|
+
lines.append("Agent Skills Security Scan Report")
|
|
627
649
|
lines.append("=" * 60)
|
|
628
650
|
lines.append(f"Skills Scanned: {report.total_skills_scanned}")
|
|
629
651
|
lines.append(f"Safe Skills: {report.safe_count}")
|
|
@@ -648,33 +670,33 @@ def generate_multi_skill_summary(report) -> str:
|
|
|
648
670
|
def main():
|
|
649
671
|
"""Main CLI entry point."""
|
|
650
672
|
parser = argparse.ArgumentParser(
|
|
651
|
-
description="
|
|
673
|
+
description="Skill Scanner - Security scanner for agent skills packages",
|
|
652
674
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
653
675
|
epilog="""
|
|
654
676
|
Examples:
|
|
655
677
|
# Scan a single skill
|
|
656
|
-
skill-
|
|
678
|
+
skill-scanner scan /path/to/skill
|
|
657
679
|
|
|
658
680
|
# Scan with behavioral analysis (dataflow tracking)
|
|
659
|
-
skill-
|
|
681
|
+
skill-scanner scan /path/to/skill --use-behavioral
|
|
660
682
|
|
|
661
683
|
# Scan with all engines (static + behavioral + LLM)
|
|
662
|
-
skill-
|
|
684
|
+
skill-scanner scan /path/to/skill --use-behavioral --use-llm
|
|
663
685
|
|
|
664
686
|
# Scan with JSON output
|
|
665
|
-
skill-
|
|
687
|
+
skill-scanner scan /path/to/skill --format json
|
|
666
688
|
|
|
667
689
|
# Scan all skills in a directory
|
|
668
|
-
skill-
|
|
690
|
+
skill-scanner scan-all /path/to/skills
|
|
669
691
|
|
|
670
692
|
# Scan recursively with all engines
|
|
671
|
-
skill-
|
|
693
|
+
skill-scanner scan-all /path/to/skills --recursive --use-behavioral --use-llm
|
|
672
694
|
|
|
673
695
|
# List available analyzers
|
|
674
|
-
skill-
|
|
696
|
+
skill-scanner list-analyzers
|
|
675
697
|
|
|
676
698
|
# Validate rule signatures
|
|
677
|
-
skill-
|
|
699
|
+
skill-scanner validate-rules
|
|
678
700
|
""",
|
|
679
701
|
)
|
|
680
702
|
|
|
@@ -728,6 +750,24 @@ Examples:
|
|
|
728
750
|
action="store_true",
|
|
729
751
|
help="Enable meta-analysis for false positive filtering and finding prioritization (requires 2+ analyzers including LLM)",
|
|
730
752
|
)
|
|
753
|
+
scan_parser.add_argument(
|
|
754
|
+
"--yara-mode",
|
|
755
|
+
choices=["strict", "balanced", "permissive"],
|
|
756
|
+
default="balanced",
|
|
757
|
+
help="YARA detection mode: strict (max security, more FPs), balanced (default), permissive (fewer FPs, may miss threats)",
|
|
758
|
+
)
|
|
759
|
+
scan_parser.add_argument(
|
|
760
|
+
"--custom-rules",
|
|
761
|
+
metavar="PATH",
|
|
762
|
+
help="Path to directory containing custom YARA rules (.yara files) to use instead of built-in rules",
|
|
763
|
+
)
|
|
764
|
+
scan_parser.add_argument(
|
|
765
|
+
"--disable-rule",
|
|
766
|
+
action="append",
|
|
767
|
+
metavar="RULE_NAME",
|
|
768
|
+
dest="disabled_rules",
|
|
769
|
+
help="Disable a specific rule by name (can be used multiple times). Example: --disable-rule YARA_script_injection",
|
|
770
|
+
)
|
|
731
771
|
|
|
732
772
|
# Scan-all command
|
|
733
773
|
scan_all_parser = subparsers.add_parser("scan-all", help="Scan multiple skill packages")
|
|
@@ -783,6 +823,24 @@ Examples:
|
|
|
783
823
|
action="store_true",
|
|
784
824
|
help="Enable meta-analysis for false positive filtering and finding prioritization (requires 2+ analyzers including LLM)",
|
|
785
825
|
)
|
|
826
|
+
scan_all_parser.add_argument(
|
|
827
|
+
"--yara-mode",
|
|
828
|
+
choices=["strict", "balanced", "permissive"],
|
|
829
|
+
default="balanced",
|
|
830
|
+
help="YARA detection mode: strict (max security, more FPs), balanced (default), permissive (fewer FPs, may miss threats)",
|
|
831
|
+
)
|
|
832
|
+
scan_all_parser.add_argument(
|
|
833
|
+
"--custom-rules",
|
|
834
|
+
metavar="PATH",
|
|
835
|
+
help="Path to directory containing custom YARA rules (.yara files) to use instead of built-in rules",
|
|
836
|
+
)
|
|
837
|
+
scan_all_parser.add_argument(
|
|
838
|
+
"--disable-rule",
|
|
839
|
+
action="append",
|
|
840
|
+
metavar="RULE_NAME",
|
|
841
|
+
dest="disabled_rules",
|
|
842
|
+
help="Disable a specific rule by name (can be used multiple times). Example: --disable-rule YARA_script_injection",
|
|
843
|
+
)
|
|
786
844
|
|
|
787
845
|
# List analyzers command
|
|
788
846
|
subparsers.add_parser("list-analyzers", help="List available analyzers")
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
# SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
|
|
17
17
|
"""
|
|
18
|
-
Configuration management for
|
|
18
|
+
Configuration management for Skill Scanner.
|
|
19
19
|
|
|
20
20
|
Mirrors MCP Scanner's config structure.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
from .config import Config
|
|
24
|
-
from .constants import
|
|
24
|
+
from .constants import SkillScannerConstants
|
|
25
25
|
|
|
26
|
-
__all__ = ["Config", "
|
|
26
|
+
__all__ = ["Config", "SkillScannerConstants"]
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
|
|
17
17
|
"""
|
|
18
|
-
Configuration class for
|
|
18
|
+
Configuration class for Skill Scanner.
|
|
19
19
|
|
|
20
20
|
Based on MCP Scanner's Config structure.
|
|
21
21
|
"""
|
|
@@ -28,7 +28,7 @@ from pathlib import Path
|
|
|
28
28
|
@dataclass
|
|
29
29
|
class Config:
|
|
30
30
|
"""
|
|
31
|
-
Configuration for
|
|
31
|
+
Configuration for Skill Scanner.
|
|
32
32
|
|
|
33
33
|
Mirrors MCP Scanner's Config class structure.
|
|
34
34
|
"""
|