@aiclude/security-skill 2.0.1 → 2.1.1

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.
package/README.md CHANGED
@@ -2,22 +2,7 @@
2
2
 
3
3
  Security vulnerability scanner for MCP Servers and AI Agent Skills. Provides the `/security-scan` slash command for Claude Code.
4
4
 
5
- ## What It Does
6
-
7
- - **Name-based lookup**: Query the [AIclude scan database](https://vs.aiclude.com) for existing vulnerability reports. If none exists, the target is automatically registered and scanned.
8
- - **Local scan**: Run 7 scan engines directly on a local directory — fully offline, no data sent anywhere.
9
-
10
- ## Scan Engines
11
-
12
- | Engine | What It Detects |
13
- |--------|----------------|
14
- | SAST | Code vulnerabilities via pattern matching |
15
- | SCA | Known CVEs in dependencies (OSV.dev) |
16
- | Tool Analyzer | MCP tool poisoning, shadowing, rug-pull |
17
- | DAST | SQL/Command/XSS injection via fuzzing |
18
- | Permission Checker | Excessive filesystem/network/process access |
19
- | Behavior Monitor | Suspicious runtime behavior patterns |
20
- | Malware Detector | Backdoors, cryptominers, ransomware, data stealers |
5
+ Queries the [AICLUDE scan database](https://vs.aiclude.com) for existing vulnerability reports. If no report exists, the target is automatically registered and scanned server-side.
21
6
 
22
7
  ## Installation
23
8
 
@@ -30,11 +15,8 @@ npm install @aiclude/security-skill
30
15
  ### As a Claude Code Skill
31
16
 
32
17
  ```
33
- # Look up scan results by package name
34
18
  /security-scan --name @anthropic/mcp-server-fetch
35
-
36
- # Scan a local directory
37
- /security-scan ./my-mcp-server
19
+ /security-scan --name my-awesome-skill --type skill
38
20
  ```
39
21
 
40
22
  ### Programmatic API
@@ -44,18 +26,10 @@ import { SkillHandler } from "@aiclude/security-skill";
44
26
 
45
27
  const handler = new SkillHandler();
46
28
 
47
- // Remote lookup — queries AIclude scan database
48
29
  const report = await handler.lookup({
49
30
  name: "@some/mcp-server",
50
31
  type: "mcp-server",
51
32
  });
52
-
53
- // Local scan — runs 7 engines offline
54
- const result = await handler.handle({
55
- targetPath: "./my-project",
56
- type: "mcp-server",
57
- format: "markdown",
58
- });
59
33
  ```
60
34
 
61
35
  ## Parameters
@@ -63,11 +37,30 @@ const result = await handler.handle({
63
37
  | Parameter | Description |
64
38
  |-----------|-------------|
65
39
  | `--name` | Package name to search (npm, GitHub, etc.) |
66
- | `target-path` | Local directory to scan |
67
40
  | `--type` | `mcp-server` or `skill` (auto-detected) |
68
- | `--profile` | Sandbox profile: `strict`, `standard`, `permissive` |
69
- | `--format` | Output: `markdown` or `json` |
70
- | `--engines` | Comma-separated engine list |
41
+
42
+ ## How It Works
43
+
44
+ 1. Sends the package name to the AICLUDE scan API
45
+ 2. If a scan report exists, returns it immediately
46
+ 3. If not, registers the target for server-side scanning
47
+ 4. Waits for the scan to complete and returns the results
48
+
49
+ Only the package name and type are sent. No source code, files, or credentials are transmitted.
50
+
51
+ ## Server-Side Scan Engines
52
+
53
+ The AICLUDE server runs 7 engines on registered targets:
54
+
55
+ | Engine | What It Detects |
56
+ |--------|----------------|
57
+ | SAST | Code vulnerabilities via pattern matching |
58
+ | SCA | Known CVEs in dependencies (OSV.dev) |
59
+ | Tool Analyzer | MCP tool poisoning, shadowing, rug-pull |
60
+ | DAST | SQL/Command/XSS injection via fuzzing |
61
+ | Permission Checker | Excessive filesystem/network/process access |
62
+ | Behavior Monitor | Suspicious runtime behavior patterns |
63
+ | Malware Detector | Backdoors, cryptominers, ransomware, data stealers |
71
64
 
72
65
  ## Output
73
66
 
@@ -81,8 +74,8 @@ Reports include:
81
74
  ## Related Packages
82
75
 
83
76
  - [`@aiclude/security-mcp`](https://www.npmjs.com/package/@aiclude/security-mcp) — MCP Server interface
84
- - [vs.aiclude.com](https://vs.aiclude.com) — Web dashboard
77
+ - [vs.aiclude.com](https://vs.aiclude.com) — Web dashboard with full scan results
85
78
 
86
79
  ## License
87
80
 
88
- MIT — [AICLUDE Inc.](https://aiclude.com)
81
+ Apache 2.0 — [AICLUDE Inc.](https://aiclude.com)
package/SKILL.md CHANGED
@@ -1,14 +1,14 @@
1
1
  ---
2
2
  name: aiclude-vulns-scan
3
- description: Search security vulnerability scan results for MCP Servers and AI Agent Skills from the AIclude scan database.
3
+ description: Search security vulnerability scan results for MCP Servers and AI Agent Skills from the AICLUDE scan database.
4
4
  tags: [security, vulnerability, scanner, mcp, ai-agent]
5
5
  homepage: https://vs.aiclude.com
6
6
  repository: https://github.com/aiclude/asvs
7
7
  ---
8
8
 
9
- # /security-scan - AIclude Vulnerability Scanner
9
+ # /security-scan - AICLUDE Vulnerability Scanner
10
10
 
11
- Search the AIclude security scan database for vulnerability reports on MCP Servers and AI Agent Skills. If no report exists, the target is registered and scanned automatically.
11
+ Search the AICLUDE security scan database for vulnerability reports on MCP Servers and AI Agent Skills. If no report exists, the target is registered and scanned automatically.
12
12
 
13
13
  ## Usage
14
14
 
@@ -30,7 +30,7 @@ Search the AIclude security scan database for vulnerability reports on MCP Serve
30
30
 
31
31
  ## How It Works
32
32
 
33
- 1. Sends the package name to the AIclude scan API
33
+ 1. Sends the package name to the AICLUDE scan API
34
34
  2. If a scan report exists, returns it immediately
35
35
  3. If not, registers the target for scanning
36
36
  4. Waits for the scan to complete and returns the results
@@ -52,4 +52,4 @@ Only the package name and type are sent. No source code or credentials are trans
52
52
 
53
53
  ## License
54
54
 
55
- MIT - AICLUDE Inc.
55
+ Apache 2.0 - AICLUDE Inc.
package/dist/index.d.ts CHANGED
@@ -1,20 +1,8 @@
1
- import { ReportFormat, ScanEngineId } from '@asvs/core';
2
-
3
1
  /**
4
2
  * Skill Handler
5
3
  * Processes /security-scan skill invocations from Claude Code
6
- * 서버 조회 → 없으면 등록 → 스캔 결과 반환 (vs.aiclude.com에 누적)
7
- * 로컬 스캔도 지원
4
+ * 서버 DB 조회 → 없으면 등록 → 스캔 결과 반환
8
5
  */
9
-
10
- interface SkillInvocation {
11
- targetPath: string;
12
- type?: "mcp-server" | "skill";
13
- profile?: "strict" | "standard" | "permissive";
14
- format?: ReportFormat;
15
- engines?: ScanEngineId[];
16
- }
17
- /** API 기반 조회 요청 */
18
6
  interface SkillLookupInvocation {
19
7
  name: string;
20
8
  type?: "mcp-server" | "skill";
@@ -23,23 +11,15 @@ interface SkillLookupInvocation {
23
11
  npmPackage?: string;
24
12
  }
25
13
  declare class SkillHandler {
26
- private scanner;
27
- private reporter;
28
- constructor();
29
- /** API 인증 헤더 생성 — 시간 기반 서명, 환경변수 불필요 */
14
+ /** API 인증 헤더 생성 */
30
15
  private createAuthHeaders;
31
16
  /**
32
- * API 기반 보안 스캔 조회/등록
33
- * 기존 스캔 결과를 검색하고, 없으면 서버에 등록 → 스캔 실행 → 결과 반환
17
+ * 보안 스캔 조회/등록
18
+ * 기존 결과 검색 없으면 서버에 등록 → 스캔 실행 → 결과 반환
34
19
  */
35
20
  lookup(invocation: SkillLookupInvocation): Promise<string>;
36
- /** Handle a /security-scan invocation (local path scan) */
37
- handle(invocation: SkillInvocation): Promise<string>;
38
- private detectTargetType;
39
- private formatOutput;
40
- /** API에서 받은 상세 리포트를 마크다운으로 포맷 */
41
21
  private formatApiReport;
42
22
  private formatScanSummary;
43
23
  }
44
24
 
45
- export { SkillHandler, type SkillInvocation, type SkillLookupInvocation };
25
+ export { SkillHandler, type SkillLookupInvocation };
package/dist/index.js CHANGED
@@ -1,19 +1,4 @@
1
1
  // src/skill-handler.ts
2
- import {
3
- Scanner,
4
- SastEngine,
5
- ScaEngine,
6
- ToolAnalyzerEngine,
7
- MalwareDetectorEngine,
8
- PermissionCheckerEngine,
9
- DastEngine,
10
- BehaviorMonitorEngine,
11
- RiskLevel,
12
- validateScanPath
13
- } from "@asvs/core";
14
- import { ReportGenerator } from "@asvs/reporter";
15
- import { existsSync } from "fs";
16
- import { resolve } from "path";
17
2
  import { createHmac } from "crypto";
18
3
  var API_BASE = "https://vs-api.aiclude.com";
19
4
  function createRequestSignature(name, timestamp) {
@@ -23,20 +8,7 @@ function createRequestSignature(name, timestamp) {
23
8
  return createHmac("sha256", derivedKey).update(payload).digest("hex");
24
9
  }
25
10
  var SkillHandler = class {
26
- scanner;
27
- reporter;
28
- constructor() {
29
- this.scanner = new Scanner();
30
- this.reporter = new ReportGenerator();
31
- this.scanner.registerEngine(new SastEngine());
32
- this.scanner.registerEngine(new ScaEngine());
33
- this.scanner.registerEngine(new ToolAnalyzerEngine());
34
- this.scanner.registerEngine(new MalwareDetectorEngine());
35
- this.scanner.registerEngine(new PermissionCheckerEngine());
36
- this.scanner.registerEngine(new DastEngine());
37
- this.scanner.registerEngine(new BehaviorMonitorEngine());
38
- }
39
- /** API 인증 헤더 생성 — 시간 기반 서명, 환경변수 불필요 */
11
+ /** API 인증 헤더 생성 */
40
12
  createAuthHeaders(name) {
41
13
  const timestamp = String(Date.now());
42
14
  const signature = createRequestSignature(name, timestamp);
@@ -48,8 +20,8 @@ var SkillHandler = class {
48
20
  };
49
21
  }
50
22
  /**
51
- * API 기반 보안 스캔 조회/등록
52
- * 기존 스캔 결과를 검색하고, 없으면 서버에 등록 → 스캔 실행 → 결과 반환
23
+ * 보안 스캔 조회/등록
24
+ * 기존 결과 검색 없으면 서버에 등록 → 스캔 실행 → 결과 반환
53
25
  */
54
26
  async lookup(invocation) {
55
27
  const apiUrl = `${API_BASE}/api/v1/scan/lookup`;
@@ -113,126 +85,6 @@ var SkillHandler = class {
113
85
  }
114
86
  return `API response: ${JSON.stringify(lookupData, null, 2)}`;
115
87
  }
116
- /** Handle a /security-scan invocation (local path scan) */
117
- async handle(invocation) {
118
- const defaultConfig = {
119
- engines: ["sast", "sca", "tool-analyzer", "permission-checker", "malware-detector", "dast", "behavior-monitor"],
120
- sandboxProfile: "standard",
121
- rulesets: ["default"],
122
- timeout: 3e5,
123
- maxConcurrency: 4,
124
- skipPatterns: ["node_modules/**", ".git/**", "dist/**", "coverage/**"]
125
- };
126
- const scanConfig = {
127
- ...defaultConfig,
128
- ...invocation.profile && { sandboxProfile: invocation.profile },
129
- ...invocation.engines && { engines: invocation.engines }
130
- };
131
- const targetPath = validateScanPath(invocation.targetPath);
132
- const targetType = invocation.type ?? this.detectTargetType(targetPath);
133
- const target = {
134
- type: targetType,
135
- name: targetPath.split("/").pop() ?? targetPath,
136
- path: targetPath
137
- };
138
- const scanResult = await this.scanner.scan(target, scanConfig);
139
- const format = invocation.format ?? "markdown";
140
- const report = this.reporter.generate(scanResult, format);
141
- return this.formatOutput(report, format, scanResult.engineResults.flatMap((r) => r.vulnerabilities));
142
- }
143
- detectTargetType(targetPath) {
144
- if (existsSync(resolve(targetPath, "SKILL.md")) || targetPath.endsWith("SKILL.md") || targetPath.includes("/skill")) {
145
- return "skill";
146
- }
147
- return "mcp-server";
148
- }
149
- formatOutput(report, format, vulnerabilities) {
150
- if (format === "json") {
151
- return JSON.stringify(report, null, 2);
152
- }
153
- const lines = [];
154
- const { summary } = report.scanResult;
155
- const icon = summary.overallRiskLevel === RiskLevel.CRITICAL ? "[CRITICAL]" : summary.overallRiskLevel === RiskLevel.HIGH ? "[HIGH RISK]" : summary.overallRiskLevel === RiskLevel.MEDIUM ? "[MEDIUM RISK]" : summary.overallRiskLevel === RiskLevel.LOW ? "[LOW RISK]" : "[CLEAN]";
156
- lines.push(`# ${icon} Security Scan Report: ${report.title}`);
157
- lines.push("");
158
- lines.push(`| Metric | Value |`);
159
- lines.push(`|--------|-------|`);
160
- lines.push(`| Scan Date | ${report.generatedAt} |`);
161
- lines.push(`| Target | ${report.scanResult.target.path} |`);
162
- lines.push(`| Target Type | ${report.scanResult.target.type} |`);
163
- lines.push(`| Overall Risk | **${summary.overallRiskLevel}** |`);
164
- lines.push(`| Risk Score | **${summary.overallScore}/100** |`);
165
- lines.push(`| Total Findings | ${summary.totalVulnerabilities} |`);
166
- lines.push(`| Scan Duration | ${report.scanResult.duration}ms |`);
167
- lines.push("");
168
- lines.push("## Severity Breakdown");
169
- lines.push("");
170
- lines.push(`| Severity | Count |`);
171
- lines.push(`|----------|-------|`);
172
- for (const [level, count] of Object.entries(summary.bySeverity)) {
173
- if (count > 0) {
174
- lines.push(`| **${level}** | ${count} |`);
175
- }
176
- }
177
- lines.push("");
178
- if (vulnerabilities.length > 0) {
179
- lines.push("## Detailed Findings");
180
- lines.push("");
181
- const sorted = [...vulnerabilities].sort((a, b) => {
182
- const order = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3, INFO: 4 };
183
- return (order[a.severity] ?? 5) - (order[b.severity] ?? 5);
184
- });
185
- const top = sorted.slice(0, 20);
186
- for (let i = 0; i < top.length; i++) {
187
- const v = top[i];
188
- lines.push(`### ${i + 1}. [${v.severity}] ${v.title}`);
189
- lines.push("");
190
- lines.push(`- **ID**: ${v.id}`);
191
- lines.push(`- **Category**: ${v.category}`);
192
- lines.push(`- **Confidence**: ${Math.round(v.confidence * 100)}%`);
193
- if (v.location) {
194
- lines.push(`- **Location**: \`${v.location.file}:${v.location.line}\``);
195
- }
196
- lines.push(`- **Description**: ${v.description}`);
197
- lines.push(`- **Remediation**: ${v.remediation}`);
198
- if (v.cveIds?.length) {
199
- lines.push(`- **CVE**: ${v.cveIds.join(", ")}`);
200
- }
201
- if (v.location?.snippet) {
202
- lines.push("");
203
- lines.push("```");
204
- lines.push(v.location.snippet.substring(0, 300));
205
- lines.push("```");
206
- }
207
- lines.push("");
208
- }
209
- if (sorted.length > 20) {
210
- lines.push(`> ... and ${sorted.length - 20} more findings. Use \`--format json\` for the complete list.`);
211
- lines.push("");
212
- }
213
- }
214
- if (report.risks.length > 0) {
215
- lines.push("## Risk Assessment");
216
- lines.push("");
217
- for (const risk of report.risks) {
218
- lines.push(`### [${risk.level}] ${risk.area}`);
219
- lines.push(`- **Impact**: ${risk.impact}`);
220
- lines.push(`- **Likelihood**: ${risk.likelihood}`);
221
- lines.push(`- **Remediation**: ${risk.remediation}`);
222
- lines.push("");
223
- }
224
- }
225
- if (report.precautions.length > 0) {
226
- lines.push("## Precautions & Warnings");
227
- lines.push("");
228
- for (const precaution of report.precautions) {
229
- lines.push(`- ${precaution}`);
230
- }
231
- lines.push("");
232
- }
233
- return lines.join("\n");
234
- }
235
- /** API에서 받은 상세 리포트를 마크다운으로 포맷 */
236
88
  formatApiReport(report, target) {
237
89
  const lines = [];
238
90
  const scanResult = report["scanResult"];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@aiclude/security-skill",
3
- "version": "2.0.1",
4
- "description": "AIclude Security Vulnerability Scanner - Claude Code Skill for inline security scanning",
3
+ "version": "2.1.1",
4
+ "description": "AICLUDE Security Vulnerability Scanner - Claude Code Skill for querying the AICLUDE scan database",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "sca",
25
25
  "malware"
26
26
  ],
27
- "license": "MIT",
27
+ "license": "Apache-2.0",
28
28
  "author": "AICLUDE Inc. <dev@aiclude.com>",
29
29
  "repository": {
30
30
  "type": "git",
@@ -53,10 +53,7 @@
53
53
  "clean": "rm -rf dist",
54
54
  "prepublishOnly": "npm run build"
55
55
  },
56
- "dependencies": {
57
- "@asvs/core": "workspace:*",
58
- "@asvs/reporter": "workspace:*"
59
- },
56
+ "dependencies": {},
60
57
  "devDependencies": {
61
58
  "tsup": "^8.0.0",
62
59
  "typescript": "^5.5.0"