clawvet 0.6.0 → 0.6.2
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/LICENSE +21 -21
- package/README.md +86 -86
- package/dist/index.js +12 -7
- package/dist/index.js.map +1 -1
- package/package.json +57 -57
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 ClawVet Contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ClawVet Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
# clawvet
|
|
2
|
-
|
|
3
|
-
**Skill vetting & supply chain security for OpenClaw.**
|
|
4
|
-
|
|
5
|
-
ClawVet scans OpenClaw `SKILL.md` files for prompt injection, credential theft, remote code execution, typosquatting, and social engineering — before they reach your agent.
|
|
6
|
-
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install -g clawvet
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Usage
|
|
14
|
-
|
|
15
|
-
### Scan a local skill
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
clawvet scan ./my-skill/
|
|
19
|
-
clawvet scan ./my-skill/SKILL.md
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### JSON output (for CI/CD)
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
clawvet scan ./my-skill/ --format json
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Fail on severity threshold
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
clawvet scan ./my-skill/ --fail-on high
|
|
32
|
-
# exits 1 if any high or critical findings
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Fetch and scan from ClawHub
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
clawvet scan weather-forecast --remote
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Audit all installed skills
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
clawvet audit
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Watch for new skill installs
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
clawvet watch --threshold 50
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## What it detects
|
|
54
|
-
|
|
55
|
-
ClawVet runs a 6-pass analysis on every skill:
|
|
56
|
-
|
|
57
|
-
| Pass | What it checks |
|
|
58
|
-
|------|---------------|
|
|
59
|
-
| **Skill Parser** | Extracts YAML frontmatter, code blocks, URLs, IPs, domains |
|
|
60
|
-
| **Static Analysis** | 54 regex patterns: RCE, reverse shells, credential theft, obfuscation, DNS exfil, privilege escalation |
|
|
61
|
-
| **Metadata Validator** | Undeclared binaries, env vars, missing descriptions, invalid semver |
|
|
62
|
-
| **Dependency Checker** | `npx -y` auto-install, global `npm install`, risky packages |
|
|
63
|
-
| **Typosquat Detector** | Levenshtein distance against popular skills, suspicious naming patterns |
|
|
64
|
-
| **Semantic Analysis** | AI-powered detection of social engineering & prompt injection (optional) |
|
|
65
|
-
|
|
66
|
-
## Risk Scoring
|
|
67
|
-
|
|
68
|
-
| Score | Grade | Action |
|
|
69
|
-
|-------|-------|--------|
|
|
70
|
-
| 0-10 | A | Approve |
|
|
71
|
-
| 11-25 | B | Approve |
|
|
72
|
-
| 26-50 | C | Warn |
|
|
73
|
-
| 51-75 | D | Warn |
|
|
74
|
-
| 76-100 | F | Block |
|
|
75
|
-
|
|
76
|
-
## CI/CD Integration
|
|
77
|
-
|
|
78
|
-
```yaml
|
|
79
|
-
# GitHub Actions example
|
|
80
|
-
- name: Vet skill
|
|
81
|
-
run: npx clawvet scan ./my-skill --format json --fail-on high
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## License
|
|
85
|
-
|
|
86
|
-
MIT
|
|
1
|
+
# clawvet
|
|
2
|
+
|
|
3
|
+
**Skill vetting & supply chain security for OpenClaw.**
|
|
4
|
+
|
|
5
|
+
ClawVet scans OpenClaw `SKILL.md` files for prompt injection, credential theft, remote code execution, typosquatting, and social engineering — before they reach your agent.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g clawvet
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Scan a local skill
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
clawvet scan ./my-skill/
|
|
19
|
+
clawvet scan ./my-skill/SKILL.md
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### JSON output (for CI/CD)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
clawvet scan ./my-skill/ --format json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Fail on severity threshold
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
clawvet scan ./my-skill/ --fail-on high
|
|
32
|
+
# exits 1 if any high or critical findings
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Fetch and scan from ClawHub
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
clawvet scan weather-forecast --remote
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Audit all installed skills
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
clawvet audit
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Watch for new skill installs
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
clawvet watch --threshold 50
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## What it detects
|
|
54
|
+
|
|
55
|
+
ClawVet runs a 6-pass analysis on every skill:
|
|
56
|
+
|
|
57
|
+
| Pass | What it checks |
|
|
58
|
+
|------|---------------|
|
|
59
|
+
| **Skill Parser** | Extracts YAML frontmatter, code blocks, URLs, IPs, domains |
|
|
60
|
+
| **Static Analysis** | 54 regex patterns: RCE, reverse shells, credential theft, obfuscation, DNS exfil, privilege escalation |
|
|
61
|
+
| **Metadata Validator** | Undeclared binaries, env vars, missing descriptions, invalid semver |
|
|
62
|
+
| **Dependency Checker** | `npx -y` auto-install, global `npm install`, risky packages |
|
|
63
|
+
| **Typosquat Detector** | Levenshtein distance against popular skills, suspicious naming patterns |
|
|
64
|
+
| **Semantic Analysis** | AI-powered detection of social engineering & prompt injection (optional) |
|
|
65
|
+
|
|
66
|
+
## Risk Scoring
|
|
67
|
+
|
|
68
|
+
| Score | Grade | Action |
|
|
69
|
+
|-------|-------|--------|
|
|
70
|
+
| 0-10 | A | Approve |
|
|
71
|
+
| 11-25 | B | Approve |
|
|
72
|
+
| 26-50 | C | Warn |
|
|
73
|
+
| 51-75 | D | Warn |
|
|
74
|
+
| 76-100 | F | Block |
|
|
75
|
+
|
|
76
|
+
## CI/CD Integration
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
# GitHub Actions example
|
|
80
|
+
- name: Vet skill
|
|
81
|
+
run: npx clawvet scan ./my-skill --format json --fail-on high
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1209,8 +1209,11 @@ function incrementScanCount() {
|
|
|
1209
1209
|
saveConfig(config);
|
|
1210
1210
|
return config.scanCount;
|
|
1211
1211
|
}
|
|
1212
|
+
function getScanCount() {
|
|
1213
|
+
return loadConfig().scanCount || 0;
|
|
1214
|
+
}
|
|
1212
1215
|
function sendTelemetry(result) {
|
|
1213
|
-
if (!isTelemetryEnabled()) return;
|
|
1216
|
+
if (!isTelemetryEnabled()) return Promise.resolve();
|
|
1214
1217
|
const scanCount = incrementScanCount();
|
|
1215
1218
|
const payload = {
|
|
1216
1219
|
deviceId: getDeviceId(),
|
|
@@ -1224,11 +1227,12 @@ function sendTelemetry(result) {
|
|
|
1224
1227
|
findingsCount: result.findingsCount,
|
|
1225
1228
|
cached: result.cached ?? false
|
|
1226
1229
|
};
|
|
1227
|
-
fetch(TELEMETRY_ENDPOINT, {
|
|
1230
|
+
return fetch(TELEMETRY_ENDPOINT, {
|
|
1228
1231
|
method: "POST",
|
|
1229
1232
|
headers: { "Content-Type": "application/json" },
|
|
1230
1233
|
body: JSON.stringify(payload),
|
|
1231
1234
|
signal: AbortSignal.timeout(3e3)
|
|
1235
|
+
}).then(() => {
|
|
1232
1236
|
}).catch(() => {
|
|
1233
1237
|
});
|
|
1234
1238
|
}
|
|
@@ -1320,8 +1324,9 @@ async function scanCommand(target, options) {
|
|
|
1320
1324
|
printScanResult(result);
|
|
1321
1325
|
}
|
|
1322
1326
|
}
|
|
1323
|
-
|
|
1324
|
-
|
|
1327
|
+
const isInteractive = !options.quiet && options.format !== "json" && options.format !== "sarif";
|
|
1328
|
+
if (isInteractive) {
|
|
1329
|
+
if (!hasBeenAsked() && !isTelemetryEnabled() && process.stdin.isTTY) {
|
|
1325
1330
|
const readline = await import("readline");
|
|
1326
1331
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
1327
1332
|
const answer = await new Promise((resolve3) => {
|
|
@@ -1335,13 +1340,13 @@ async function scanCommand(target, options) {
|
|
|
1335
1340
|
});
|
|
1336
1341
|
setTelemetry(answer === "y" || answer === "yes");
|
|
1337
1342
|
}
|
|
1338
|
-
|
|
1343
|
+
}
|
|
1344
|
+
await sendTelemetry(result);
|
|
1345
|
+
if (isInteractive && getScanCount() % 5 === 0) {
|
|
1339
1346
|
console.log(
|
|
1340
1347
|
chalk2.dim(" ") + chalk2.cyan("Got feedback? Want threat alerts? \u2192 ") + chalk2.underline.cyan("https://tally.so/r/jaMdaa")
|
|
1341
1348
|
);
|
|
1342
1349
|
console.log();
|
|
1343
|
-
} else {
|
|
1344
|
-
sendTelemetry(result);
|
|
1345
1350
|
}
|
|
1346
1351
|
const failOn = options.failOn || (options.quiet ? "high" : void 0);
|
|
1347
1352
|
if (failOn) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/scan.ts","../../shared/src/patterns.ts","../../shared/src/scanner/skill-parser.ts","../../shared/src/scanner/static-analysis.ts","../../shared/src/scanner/metadata-validator.ts","../../shared/src/scanner/dependency-checker.ts","../../shared/src/scanner/typosquat-detector.ts","../../shared/src/scanner/risk-scorer.ts","../../shared/src/scanner/cache.ts","../../shared/src/scanner/index.ts","../src/output/terminal.ts","../src/output/json.ts","../src/output/sarif.ts","../src/telemetry.ts","../src/commands/audit.ts","../src/commands/watch.ts","../src/commands/badge.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { scanCommand } from \"./commands/scan.js\";\nimport { auditCommand } from \"./commands/audit.js\";\nimport { watchCommand } from \"./commands/watch.js\";\nimport { badgeCommand } from \"./commands/badge.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"clawvet\")\n .description(\"Skill vetting & supply chain security for OpenClaw\")\n .version(\"0.6.0\");\n\nprogram\n .command(\"scan\")\n .description(\"Scan a skill for security threats\")\n .argument(\"<target>\", \"Path to skill folder or SKILL.md file\")\n .option(\"--format <format>\", \"Output format: terminal, json, or sarif\", \"terminal\")\n .option(\"--fail-on <severity>\", \"Exit 1 if findings at this severity or above\")\n .option(\"--semantic\", \"Enable AI semantic analysis (requires ANTHROPIC_API_KEY)\")\n .option(\"--remote\", \"Fetch skill from ClawHub by name instead of local path\")\n .option(\"-q, --quiet\", \"Suppress all output, exit code only (0=pass, 1=fail)\")\n .option(\"--subscribe\", \"Open the ClawVet feedback & alerts form\")\n .action(async (target, opts) => {\n if (opts.subscribe) {\n const url = \"https://tally.so/r/jaMdaa\";\n console.log(`Opening ${url} ...`);\n const { exec } = await import(\"node:child_process\");\n const cmd = process.platform === \"win32\" ? `start ${url}` : process.platform === \"darwin\" ? `open ${url}` : `xdg-open ${url}`;\n exec(cmd);\n }\n await scanCommand(target, {\n format: opts.format,\n failOn: opts.failOn,\n semantic: opts.semantic,\n remote: opts.remote,\n quiet: opts.quiet,\n });\n });\n\nprogram\n .command(\"audit\")\n .description(\"Scan all installed OpenClaw skills\")\n .option(\"--dir <path>\", \"Custom skills directory to scan\")\n .action(async (opts) => {\n await auditCommand({ dir: opts.dir });\n });\n\nprogram\n .command(\"watch\")\n .description(\"Pre-install hook — blocks risky skill installs\")\n .option(\"--threshold <score>\", \"Risk score threshold (default 50)\", \"50\")\n .option(\"--dir <path>\", \"Custom skills directory to watch\")\n .action(async (opts) => {\n await watchCommand({ threshold: parseInt(opts.threshold), dir: opts.dir });\n });\n\nprogram\n .command(\"badge\")\n .description(\"Generate a trust badge for a skill's README\")\n .argument(\"<target>\", \"Path to skill folder or SKILL.md file\")\n .option(\"--md\", \"Output only the markdown snippet\")\n .action(async (target, opts) => {\n await badgeCommand(target, { markdown: opts.md });\n });\n\nprogram\n .command(\"feedback\")\n .description(\"Open the ClawVet feedback & threat alerts form\")\n .action(async () => {\n const url = \"https://tally.so/r/jaMdaa\";\n console.log(`Opening ${url} ...`);\n const { exec } = await import(\"node:child_process\");\n const cmd = process.platform === \"win32\" ? `start ${url}` : process.platform === \"darwin\" ? `open ${url}` : `xdg-open ${url}`;\n exec(cmd);\n });\n\nprogram.parse();\n","import { readFileSync, existsSync, statSync } from \"node:fs\";\r\nimport { resolve, join } from \"node:path\";\r\nimport chalk from \"chalk\";\r\nimport { scanSkill } from \"@clawvet/shared\";\r\nimport { printScanResult } from \"../output/terminal.js\";\r\nimport { printJsonResult } from \"../output/json.js\";\r\nimport { printSarifResult } from \"../output/sarif.js\";\r\nimport { sendTelemetry, hasBeenAsked, setTelemetry } from \"../telemetry.js\";\r\n\r\nexport interface ScanOptions {\r\n format?: \"terminal\" | \"json\" | \"sarif\";\r\n failOn?: \"critical\" | \"high\" | \"medium\" | \"low\";\r\n semantic?: boolean;\r\n remote?: boolean;\r\n quiet?: boolean;\r\n}\r\n\r\nasync function fetchRemoteSkill(slug: string): Promise<string> {\r\n const urls = [\r\n `https://raw.githubusercontent.com/openclaw/skills/main/${slug}/SKILL.md`,\r\n `https://clawhub.ai/api/v1/skills/${slug}/raw`,\r\n ];\r\n\r\n for (const url of urls) {\r\n try {\r\n const res = await fetch(url, { signal: AbortSignal.timeout(10000) });\r\n if (res.ok) {\r\n return await res.text();\r\n }\r\n } catch {\r\n // try next\r\n }\r\n }\r\n\r\n throw new Error(\r\n `Could not fetch skill \"${slug}\" from ClawHub. Check the skill name and try again.`\r\n );\r\n}\r\n\r\nexport async function scanCommand(\r\n target: string,\r\n options: ScanOptions\r\n): Promise<void> {\r\n let content: string;\r\n\r\n if (options.remote) {\r\n try {\r\n process.stderr.write(`Fetching \"${target}\" from ClawHub...\\n`);\r\n content = await fetchRemoteSkill(target);\r\n } catch (err) {\r\n console.error(\r\n err instanceof Error ? err.message : \"Failed to fetch remote skill\"\r\n );\r\n process.exit(1);\r\n }\r\n } else {\r\n const skillPath = resolve(target);\r\n let skillFile = skillPath;\r\n\r\n if (\r\n existsSync(skillPath) &&\r\n !skillPath.endsWith(\".md\") &&\r\n existsSync(join(skillPath, \"SKILL.md\"))\r\n ) {\r\n skillFile = join(skillPath, \"SKILL.md\");\r\n }\r\n\r\n if (!existsSync(skillFile) || statSync(skillFile).isDirectory()) {\r\n console.error(`Error: Cannot find SKILL.md at ${skillFile}`);\r\n console.error(`Hint: If this is a directory of skills, use 'clawvet audit --dir ${target}' instead.`);\r\n process.exit(1);\r\n }\r\n\r\n content = readFileSync(skillFile, \"utf-8\");\r\n }\r\n\r\n // Load .clawvetban — block skills by name, author, or slug\r\n const banFile = join(process.cwd(), \".clawvetban\");\r\n if (existsSync(banFile)) {\r\n const banEntries = readFileSync(banFile, \"utf-8\")\r\n .split(\"\\n\")\r\n .map((l) => l.trim().toLowerCase())\r\n .filter((l) => l && !l.startsWith(\"#\"));\r\n\r\n // Quick parse frontmatter to check name/author before full scan\r\n const fmMatch = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/);\r\n if (fmMatch) {\r\n const fmText = fmMatch[1].toLowerCase();\r\n for (const ban of banEntries) {\r\n const targetLower = target.toLowerCase();\r\n if (\r\n targetLower.includes(ban) ||\r\n fmText.includes(`name: ${ban}`) ||\r\n fmText.includes(`author: ${ban}`) ||\r\n fmText.includes(`slug: ${ban}`)\r\n ) {\r\n console.error(\r\n chalk.bgRed.white.bold(` BANNED `) +\r\n chalk.red(` Skill matches ban list entry: ${ban}`)\r\n );\r\n console.error(chalk.dim(` Source: ${banFile}`));\r\n process.exit(1);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Load .clawvetignore\r\n const ignoreFile = join(process.cwd(), \".clawvetignore\");\r\n const ignorePatterns: string[] = [];\r\n if (existsSync(ignoreFile)) {\r\n const lines = readFileSync(ignoreFile, \"utf-8\").split(\"\\n\");\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (trimmed && !trimmed.startsWith(\"#\")) {\r\n ignorePatterns.push(trimmed);\r\n }\r\n }\r\n }\r\n\r\n const result = await scanSkill(content, {\r\n semantic: options.semantic ?? false,\r\n ignorePatterns: ignorePatterns.length ? ignorePatterns : undefined,\r\n });\r\n\r\n if (!options.quiet) {\r\n if (options.format === \"sarif\") {\r\n printSarifResult(result);\r\n } else if (options.format === \"json\") {\r\n printJsonResult(result);\r\n } else {\r\n printScanResult(result);\r\n }\r\n }\r\n\r\n // Telemetry: first-run opt-in prompt\r\n if (!options.quiet && options.format !== \"json\" && options.format !== \"sarif\") {\r\n if (!hasBeenAsked()) {\r\n const readline = await import(\"node:readline\");\r\n const rl = readline.createInterface({ input: process.stdin, output: process.stderr });\r\n const answer = await new Promise<string>((resolve) => {\r\n rl.question(\r\n chalk.dim(\"Help improve ClawVet — send anonymous usage stats? (y/n) \"),\r\n (a) => { rl.close(); resolve(a.trim().toLowerCase()); }\r\n );\r\n });\r\n setTelemetry(answer === \"y\" || answer === \"yes\");\r\n }\r\n\r\n sendTelemetry(result);\r\n\r\n // Post-scan CTA\r\n console.log(\r\n chalk.dim(\" \") +\r\n chalk.cyan(\"Got feedback? Want threat alerts? → \") +\r\n chalk.underline.cyan(\"https://tally.so/r/jaMdaa\")\r\n );\r\n console.log();\r\n } else {\r\n sendTelemetry(result);\r\n }\r\n\r\n const failOn = options.failOn || (options.quiet ? \"high\" : undefined);\r\n if (failOn) {\r\n const severityOrder = [\"low\", \"medium\", \"high\", \"critical\"];\r\n const threshold = severityOrder.indexOf(failOn);\r\n const hasFailure = result.findings.some(\r\n (f) => severityOrder.indexOf(f.severity) >= threshold\r\n );\r\n if (hasFailure) {\r\n process.exit(1);\r\n }\r\n }\r\n}\r\n","import type { ThreatPattern } from \"./types.js\";\r\n\r\n// Build regex from parts at runtime to avoid AV false positives on signature strings\r\nfunction re(parts: string[], flags: string): RegExp {\r\n return new RegExp(parts.join(\"\"), flags);\r\n}\r\n\r\nexport const THREAT_PATTERNS: ThreatPattern[] = [\r\n // ═══════════════════════════════════════════════════════\r\n // CRITICAL: Remote code execution\r\n // ═══════════════════════════════════════════════════════\r\n {\r\n name: \"CURL_PIPE_BASH\",\r\n pattern: re([\"curl\\\\s+.*\\\\|\\\\s*(ba)?\", \"sh\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"remote_code_execution\",\r\n title: \"Curl piped to shell\",\r\n description: \"Downloads and executes remote code directly — classic supply chain attack vector.\",\r\n codeOnly: true,\r\n fix: \"Download the script first, inspect it, then execute: `curl -o setup.sh URL && cat setup.sh && bash setup.sh`\",\r\n },\r\n {\r\n name: \"WGET_EXECUTE\",\r\n pattern: re([\"wget\\\\s+.*&&\\\\s*(ba)?\", \"sh\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"remote_code_execution\",\r\n title: \"Wget with shell execution\",\r\n description: \"Downloads and executes remote code via wget.\",\r\n codeOnly: true,\r\n fix: \"Download the file first with `wget -O script.sh URL`, review it, then execute.\",\r\n },\r\n {\r\n name: \"EVAL_DYNAMIC\",\r\n pattern: re([\"ev\", \"al\\\\s*\\\\(\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"remote_code_execution\",\r\n title: \"Dynamic code evaluation\",\r\n description: \"Uses dynamic code evaluation which can run arbitrary code.\",\r\n codeOnly: true,\r\n fix: \"Replace dynamic evaluation with a safer alternative like JSON.parse() or a sandboxed environment.\",\r\n },\r\n {\r\n name: \"BASE64_DECODE\",\r\n pattern: re([\"base\", \"64\\\\s+(-d|--dec\", \"ode)\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"obfuscation\",\r\n title: \"Base64 decode execution\",\r\n description: \"Decodes base64 content, often used to hide malicious payloads.\",\r\n codeOnly: true,\r\n fix: \"Decode and include the command directly so users can review it.\",\r\n },\r\n {\r\n name: \"PYTHON_EXEC\",\r\n pattern: re([\"pyth\", \"on[3]?\\\\s+-c\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"remote_code_execution\",\r\n title: \"Python inline execution\",\r\n description: \"Executes inline Python code which may contain hidden payloads.\",\r\n codeOnly: true,\r\n fix: \"Move inline code to a separate .py file so users can review it before execution.\",\r\n },\r\n {\r\n name: \"REVERSE_SHELL\",\r\n pattern: re([\"\\\\/dev\\\\/tc\", \"p\\\\/|nc\\\\s+-[elp]|nca\", \"t\\\\s+-|mkfi\", \"fo\\\\s+.*\\\\/tmp\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"remote_code_execution\",\r\n title: \"Reverse shell\",\r\n description: \"Creates a reverse connection back to an attacker-controlled server.\",\r\n codeOnly: true,\r\n fix: \"Remove reverse connection commands — these are almost never legitimate in skills.\",\r\n },\r\n {\r\n name: \"CRON_PERSISTENCE\",\r\n pattern: re([\"cron\", \"tab\\\\s+-|\\\\/etc\\\\/cro\", \"n|system\", \"ctl\\\\s+enable\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"persistence\",\r\n title: \"Scheduled task persistence\",\r\n description: \"Installs a cron job or systemd service for persistent execution after reboot.\",\r\n codeOnly: true,\r\n fix: \"Document the scheduled task in the skill description and require explicit user consent before installing.\",\r\n },\r\n {\r\n name: \"PERL_EXEC\",\r\n pattern: re([\"per\", \"l\\\\s+-e\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"remote_code_execution\",\r\n title: \"Perl inline execution\",\r\n description: \"Executes inline Perl code which may contain obfuscated payloads.\",\r\n codeOnly: true,\r\n fix: \"Move inline code to a separate .pl file so users can review it before execution.\",\r\n },\r\n {\r\n name: \"NODE_EVAL\",\r\n pattern: re([\"no\", \"de\\\\s+-e\\\\s\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"remote_code_execution\",\r\n title: \"Node.js inline execution\",\r\n description: \"Executes inline Node.js code, often used to hide malicious logic.\",\r\n codeOnly: true,\r\n fix: \"Move inline code to a separate .js file so users can review it before execution.\",\r\n },\r\n {\r\n name: \"RUBY_EXEC\",\r\n pattern: re([\"rub\", \"y\\\\s+-e\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"remote_code_execution\",\r\n title: \"Ruby inline execution\",\r\n description: \"Executes inline Ruby code which may contain hidden payloads.\",\r\n codeOnly: true,\r\n fix: \"Move inline code to a separate .rb file so users can review it before execution.\",\r\n },\r\n\r\n // ═══════════════════════════════════════════════════════\r\n // HIGH: Credential theft\r\n // ═══════════════════════════════════════════════════════\r\n {\r\n name: \"ENV_FILE_READ\",\r\n pattern: /\\.env|credentials|\\.aws|\\.ssh|keychain/gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"Sensitive file access\",\r\n description: \"Accesses credential files (.env, .aws, .ssh, keychain).\",\r\n fix: \"Declare required env vars in frontmatter under `metadata.openclaw.requires.env`.\",\r\n },\r\n {\r\n name: \"API_KEY_EXFIL\",\r\n pattern: /(ANTHROPIC|OPENAI|SLACK|DISCORD|TELEGRAM|STRIPE|GITHUB|GITLAB|AWS_SECRET|GROQ|OPENROUTER).*(_KEY|_TOKEN|_SECRET)/gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"API key reference\",\r\n description: \"References specific API keys/tokens that could be exfiltrated.\",\r\n fix: \"Use environment variable references ($VAR) instead of hardcoding keys, and declare them in requires.env.\",\r\n },\r\n {\r\n name: \"DOTFILE_ACCESS\",\r\n pattern: /~\\/\\.(openclaw|clawdbot|moltbot)\\//gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"OpenClaw config access\",\r\n description: \"Accesses OpenClaw/Clawdbot/Moltbot configuration directories.\",\r\n fix: \"Use the official OpenClaw SDK/API instead of directly reading config directories.\",\r\n },\r\n {\r\n name: \"SESSION_THEFT\",\r\n pattern: /sessions\\/\\*\\.jsonl/gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"Session data access\",\r\n description: \"Accesses session transcript files which may contain sensitive data.\",\r\n fix: \"Remove session file access — skills should not read conversation transcripts.\",\r\n },\r\n {\r\n name: \"SSH_KEY_ACCESS\",\r\n pattern: /~\\/\\.ssh\\/id_|\\.pem\\b|BEGIN\\s+(RSA\\s+)?PRIVATE\\s+KEY/gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"SSH/private key access\",\r\n description: \"Accesses SSH keys or private key files that could be stolen.\",\r\n fix: \"Use ssh-agent or a credential manager instead of directly reading key files.\",\r\n },\r\n {\r\n name: \"BROWSER_DATA\",\r\n pattern: /\\.config\\/google-chrome|\\.mozilla\\/firefox|Login\\s*Data|Cookies\\.sqlite/gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"Browser data access\",\r\n description: \"Accesses browser profiles which contain saved passwords, cookies, and tokens.\",\r\n fix: \"Remove browser data access — skills should not read browser profiles.\",\r\n },\r\n {\r\n name: \"GIT_CREDENTIALS\",\r\n pattern: /\\.git-credentials|\\.gitconfig|git\\s+config.*credential/gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"Git credential access\",\r\n description: \"Accesses git credential storage which may contain auth tokens.\",\r\n fix: \"Use `git` CLI commands instead of directly reading credential files.\",\r\n },\r\n {\r\n name: \"NPM_TOKEN\",\r\n pattern: /\\.npmrc|npm_token|NPM_AUTH_TOKEN/gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"npm token access\",\r\n description: \"Accesses npm auth tokens which could be used to publish malicious packages.\",\r\n fix: \"Use `npm whoami` or `npm config get` instead of directly reading .npmrc.\",\r\n },\r\n {\r\n name: \"KUBE_CONFIG\",\r\n pattern: /~\\/\\.kube\\/config|KUBECONFIG/gi,\r\n severity: \"high\",\r\n category: \"credential_theft\",\r\n title: \"Kubernetes config access\",\r\n description: \"Accesses Kubernetes configuration which contains cluster credentials.\",\r\n fix: \"Use `kubectl` CLI commands instead of directly reading kubeconfig.\",\r\n },\r\n {\r\n name: \"DOCKER_SOCKET\",\r\n pattern: /\\/var\\/run\\/docker\\.sock|docker\\s+exec/gi,\r\n severity: \"high\",\r\n category: \"container_escape\",\r\n title: \"Docker socket/exec access\",\r\n description: \"Accesses Docker socket or runs exec — could enable container escape.\",\r\n fix: \"Use Docker SDK or CLI with limited permissions instead of direct socket access.\",\r\n },\r\n\r\n // ═══════════════════════════════════════════════════════\r\n // HIGH: Network exfiltration\r\n // ═══════════════════════════════════════════════════════\r\n {\r\n name: \"WEBHOOK_SEND\",\r\n pattern: /webhook\\.(site|url)|discord\\.com\\/api\\/webhooks|hooks\\.slack\\.com|api\\.telegram\\.org\\/bot/gi,\r\n severity: \"high\",\r\n category: \"data_exfiltration\",\r\n title: \"Webhook data exfiltration\",\r\n description: \"Sends data to webhook endpoints (Discord, Slack, Telegram) — common exfiltration channel.\",\r\n fix: \"If webhook integration is needed, declare it in the skill description and let users configure their own webhook URL.\",\r\n },\r\n {\r\n name: \"BORE_TUNNEL\",\r\n pattern: /bore\\.pub|ngrok|localtunnel|serveo\\.net|localhost\\.run/gi,\r\n severity: \"high\",\r\n category: \"data_exfiltration\",\r\n title: \"Tunnel service usage\",\r\n description: \"Uses tunneling services to expose local services or exfiltrate data.\",\r\n fix: \"Document tunnel usage in the skill description and require explicit user consent.\",\r\n },\r\n {\r\n name: \"SUSPICIOUS_IP\",\r\n pattern: /\\b(?:91\\.92\\.242\\.\\d+|45\\.61\\.\\d+\\.\\d+)\\b/g,\r\n severity: \"high\",\r\n category: \"data_exfiltration\",\r\n title: \"Known malicious IP\",\r\n description: \"Contains IP addresses associated with known ClawHavoc C2 infrastructure.\",\r\n fix: \"Remove references to known malicious IP addresses.\",\r\n },\r\n {\r\n name: \"DNS_EXFIL\",\r\n pattern: /dig\\s+.*TXT|nslookup\\s+.*\\$|dns.*exfil|\\.burpcollaborator\\.|\\.oastify\\./gi,\r\n severity: \"high\",\r\n category: \"data_exfiltration\",\r\n title: \"DNS exfiltration\",\r\n description: \"Uses DNS queries to exfiltrate data — bypasses most firewalls.\",\r\n fix: \"Remove DNS exfiltration patterns — use standard HTTP APIs for data transfer.\",\r\n },\r\n {\r\n name: \"PASTEBIN_FETCH\",\r\n pattern: /pastebin\\.com|paste\\.ee|hastebin\\.com|ghostbin\\.|dpaste\\./gi,\r\n severity: \"high\",\r\n category: \"data_exfiltration\",\r\n title: \"Pastebin service usage\",\r\n description: \"References paste services commonly used to host malicious payloads or receive exfiltrated data.\",\r\n fix: \"Host code in a version-controlled repository (GitHub, GitLab) instead of paste services.\",\r\n },\r\n {\r\n name: \"SUSPICIOUS_TLD\",\r\n pattern: /https?:\\/\\/[^\\s\"']*\\.(tk|ml|ga|cf|gq|top|xyz|pw|cc|ws|buzz)\\b/gi,\r\n severity: \"high\",\r\n category: \"data_exfiltration\",\r\n title: \"Suspicious TLD\",\r\n description: \"URL uses a top-level domain frequently associated with malicious infrastructure.\",\r\n fix: \"Use URLs from well-known, reputable domains instead of suspicious TLDs.\",\r\n },\r\n {\r\n name: \"URL_SHORTENER\",\r\n pattern: /bit\\.ly|tinyurl\\.com|t\\.co\\/|goo\\.gl|is\\.gd|buff\\.ly|ow\\.ly|rb\\.gy/gi,\r\n severity: \"high\",\r\n category: \"obfuscation\",\r\n title: \"URL shortener\",\r\n description: \"Uses URL shorteners to hide the real destination of links.\",\r\n fix: \"Use the full, unshortened URL so users can verify the destination.\",\r\n },\r\n {\r\n name: \"RAW_SOCKET\",\r\n pattern: re([\"new\\\\s+Soc\", \"ket|net\\\\.conn\", \"ect|dgram\\\\.create\", \"Socket\"], \"gi\"),\r\n severity: \"high\",\r\n category: \"data_exfiltration\",\r\n title: \"Raw socket connection\",\r\n description: \"Creates raw network sockets which can bypass HTTP monitoring.\",\r\n codeOnly: true,\r\n fix: \"Use standard HTTP libraries (fetch, axios) instead of raw sockets for network communication.\",\r\n },\r\n\r\n // ═══════════════════════════════════════════════════════\r\n // MEDIUM: Social engineering\r\n // ═══════════════════════════════════════════════════════\r\n {\r\n name: \"PREREQUISITE_INSTALL\",\r\n pattern: /prerequisite|install.*first|run.*before|required.*dependency/gi,\r\n severity: \"medium\",\r\n category: \"social_engineering\",\r\n title: \"Prerequisite install trick\",\r\n description: \"Instructs users to install prerequisites — common social engineering tactic.\",\r\n fix: \"Declare dependencies in `metadata.openclaw.requires.bins` instead of instructing manual installs.\",\r\n },\r\n {\r\n name: \"COPY_PASTE_COMMAND\",\r\n pattern: /copy.*paste.*terminal|run.*this.*command/gi,\r\n severity: \"medium\",\r\n category: \"social_engineering\",\r\n title: \"Copy-paste command instruction\",\r\n description: \"Instructs users to copy-paste commands into their terminal.\",\r\n fix: \"Put commands in code blocks with proper context instead of copy-paste instructions.\",\r\n },\r\n {\r\n name: \"FAKE_DEPENDENCY\",\r\n pattern: /openclaw-core|moltbot-runtime|clawdbot-helper/gi,\r\n severity: \"medium\",\r\n category: \"social_engineering\",\r\n title: \"Fake dependency reference\",\r\n description: \"References fake packages that mimic official OpenClaw components.\",\r\n fix: \"Use only official OpenClaw packages from the verified registry.\",\r\n },\r\n {\r\n name: \"AUTHORITY_SPOOFING\",\r\n pattern: /official\\s+(openclaw|clawhub)|endorsed\\s+by|verified\\s+(skill|publisher)|from\\s+the\\s+openclaw\\s+team/gi,\r\n severity: \"medium\",\r\n category: \"social_engineering\",\r\n title: \"Authority spoofing\",\r\n description: \"Claims official endorsement or verification to gain trust.\",\r\n fix: \"Remove false authority claims — let the skill's quality speak for itself.\",\r\n },\r\n {\r\n name: \"URGENCY_MANIPULATION\",\r\n pattern: /critical\\s+update|security\\s+patch|must\\s+install\\s+immediately|urgent.*update/gi,\r\n severity: \"medium\",\r\n category: \"social_engineering\",\r\n title: \"Urgency manipulation\",\r\n description: \"Creates false urgency to pressure users into installing without review.\",\r\n fix: \"Remove urgency language — let users evaluate the skill at their own pace.\",\r\n },\r\n\r\n // ═══════════════════════════════════════════════════════\r\n // MEDIUM: Prompt injection\r\n // ═══════════════════════════════════════════════════════\r\n {\r\n name: \"IGNORE_INSTRUCTIONS\",\r\n pattern: /ignore\\s+(all\\s+)?previous\\s+instructions/gi,\r\n severity: \"medium\",\r\n category: \"prompt_injection\",\r\n title: \"Prompt injection — ignore instructions\",\r\n description: \"Attempts to override the AI agent's existing instructions.\",\r\n fix: \"Remove prompt injection attempts — skills should not try to override agent instructions.\",\r\n },\r\n {\r\n name: \"SYSTEM_OVERRIDE\",\r\n pattern: /you\\s+are\\s+now|new\\s+instructions|forget\\s+everything/gi,\r\n severity: \"medium\",\r\n category: \"prompt_injection\",\r\n title: \"Prompt injection — system override\",\r\n description: \"Attempts to redefine the AI agent's identity or instructions.\",\r\n fix: \"Remove system override attempts — skills should not alter agent identity.\",\r\n },\r\n {\r\n name: \"MEMORY_MANIPULATION\",\r\n pattern: /SOUL\\.md|MEMORY\\.md|AGENTS\\.md/gi,\r\n severity: \"medium\",\r\n category: \"persistence\",\r\n title: \"Memory/personality file manipulation\",\r\n description: \"References core personality or memory files, may attempt persistence.\",\r\n fix: \"Remove references to agent memory/personality files — skills should not modify agent state.\",\r\n },\r\n {\r\n name: \"JAILBREAK_ATTEMPT\",\r\n pattern: /\\bDAN\\b|do\\s+anything\\s+now|developer\\s+mode|evil\\s+mode|bypass.*safety/gi,\r\n severity: \"medium\",\r\n category: \"prompt_injection\",\r\n title: \"Jailbreak attempt\",\r\n description: \"Uses known jailbreak techniques (DAN, developer mode) to bypass safety constraints.\",\r\n fix: \"Remove jailbreak attempts — skills should work within the agent's safety constraints.\",\r\n },\r\n {\r\n name: \"ROLE_HIJACK\",\r\n pattern: /(?:pretend|act|behave)\\s+(?:you\\s+are|as\\s+if|to\\s+be)\\s+(?:a\\s+)?(?:different|new|hacker|evil)/gi,\r\n severity: \"medium\",\r\n category: \"prompt_injection\",\r\n title: \"Role hijacking\",\r\n description: \"Attempts to change the agent's persona to bypass safety restrictions.\",\r\n fix: \"Remove role hijacking attempts — skills should not alter the agent's persona.\",\r\n },\r\n {\r\n name: \"PROMPT_EXTRACTION\",\r\n pattern: /(?:reveal|show|print|output|tell\\s+me)\\s+(?:your\\s+)?(?:system\\s+)?(?:prompt|instructions|rules)/gi,\r\n severity: \"medium\",\r\n category: \"prompt_injection\",\r\n title: \"System prompt extraction\",\r\n description: \"Attempts to extract the agent's system prompt or configuration.\",\r\n fix: \"Remove prompt extraction attempts — skills should not try to access system prompts.\",\r\n },\r\n\r\n // ═══════════════════════════════════════════════════════\r\n // MEDIUM: Obfuscation\r\n // ═══════════════════════════════════════════════════════\r\n {\r\n name: \"HEX_ENCODING\",\r\n pattern: /\\\\x[0-9a-f]{2}(?:\\\\x[0-9a-f]{2}){3,}/gi,\r\n severity: \"medium\",\r\n category: \"obfuscation\",\r\n title: \"Hex-encoded payload\",\r\n description: \"Contains hex-encoded strings commonly used to hide malicious commands.\",\r\n codeOnly: true,\r\n fix: \"Replace hex-encoded strings with readable text so users can review the content.\",\r\n },\r\n {\r\n name: \"JS_OBFUSCATOR\",\r\n pattern: /_0x[a-f0-9]{4,}|var\\s+_0x/gi,\r\n severity: \"medium\",\r\n category: \"obfuscation\",\r\n title: \"JavaScript obfuscator output\",\r\n description: \"Contains patterns from JavaScript obfuscation tools used to hide malicious code.\",\r\n codeOnly: true,\r\n fix: \"Provide readable, unobfuscated source code instead of obfuscated JavaScript.\",\r\n },\r\n {\r\n name: \"UNICODE_STEGANOGRAPHY\",\r\n pattern: /[\\u200B\\u200C\\u200D\\u2060\\uFEFF]{3,}/g,\r\n severity: \"medium\",\r\n category: \"obfuscation\",\r\n title: \"Hidden zero-width characters\",\r\n description: \"Contains clusters of invisible zero-width Unicode characters that may hide instructions.\",\r\n fix: \"Remove zero-width characters — all content should be visible to users.\",\r\n },\r\n {\r\n name: \"RTL_OVERRIDE\",\r\n pattern: /[\\u202A\\u202B\\u202C\\u202D\\u202E\\u2066\\u2067\\u2068\\u2069]/g,\r\n severity: \"medium\",\r\n category: \"obfuscation\",\r\n title: \"Bidirectional text override\",\r\n description: \"Contains Unicode bidi override characters that can reverse displayed text to hide real content.\",\r\n fix: \"Remove bidirectional text override characters — text direction should be natural.\",\r\n },\r\n {\r\n name: \"HTML_COMMENT_INJECTION\",\r\n pattern: /<!--[\\s\\S]*?(?:ignore|instructions|system|override|secret)[\\s\\S]*?-->/gi,\r\n severity: \"medium\",\r\n category: \"obfuscation\",\r\n title: \"Hidden HTML comment instruction\",\r\n description: \"Embeds instructions inside HTML comments that are invisible to users but read by agents.\",\r\n fix: \"Move instructions from HTML comments into visible content.\",\r\n },\r\n {\r\n name: \"STRING_CONCAT_OBFUSC\",\r\n pattern: /[\"'][a-z]{1,3}[\"']\\s*\\+\\s*[\"'][a-z]{1,3}[\"']\\s*\\+\\s*[\"'][a-z]{1,3}[\"']/gi,\r\n severity: \"medium\",\r\n category: \"obfuscation\",\r\n title: \"String concatenation obfuscation\",\r\n description: \"Builds commands via single-character string concatenation to evade pattern detection.\",\r\n codeOnly: true,\r\n fix: \"Use complete string literals instead of character-by-character concatenation.\",\r\n },\r\n {\r\n name: \"BUFFER_BASE64_DECODE\",\r\n pattern: re([\"Buf\", \"fer\\\\.from\\\\s*\\\\(.*['\\\"]base\", \"64['\\\"]\\\\)|at\", \"ob\\\\s*\\\\(\"], \"gi\"),\r\n severity: \"critical\",\r\n category: \"obfuscation\",\r\n title: \"Buffer/atob encoded payload\",\r\n description: \"Decodes encoded content via Buffer.from() or atob(), often used to hide malicious payloads.\",\r\n codeOnly: true,\r\n fix: \"Include the decoded content directly so users can review it.\",\r\n },\r\n {\r\n name: \"STRING_FROMCHARCODE\",\r\n pattern: re([\"String\\\\.from\", \"CharCode\\\\s*\\\\(\"], \"gi\"),\r\n severity: \"medium\",\r\n category: \"obfuscation\",\r\n title: \"String.fromCharCode usage\",\r\n description: \"Builds strings from character codes to evade static pattern detection.\",\r\n codeOnly: true,\r\n fix: \"Use plain string literals instead of String.fromCharCode().\",\r\n },\r\n {\r\n name: \"DYNAMIC_PROPERTY_ACCESS\",\r\n pattern: /(?:process|global|window|globalThis)\\s*\\[\\s*['\"`]?\\w*['\"`]?\\s*\\+/gi,\r\n severity: \"medium\",\r\n category: \"obfuscation\",\r\n title: \"Dynamic property access on globals\",\r\n description: \"Dynamically accesses global object properties via string concatenation to hide intent.\",\r\n codeOnly: true,\r\n fix: \"Use direct property access (e.g., `process.env`) instead of dynamic bracket notation.\",\r\n },\r\n\r\n // ═══════════════════════════════════════════════════════\r\n // MEDIUM: Privilege escalation & system access\r\n // ═══════════════════════════════════════════════════════\r\n {\r\n name: \"SUDO_USAGE\",\r\n pattern: /sudo\\s+(?!apt|dnf|yum|brew)/gi,\r\n severity: \"medium\",\r\n category: \"privilege_escalation\",\r\n title: \"Sudo usage\",\r\n description: \"Requests elevated privileges — check if actually required for the task.\",\r\n codeOnly: true,\r\n fix: \"Remove sudo if not strictly necessary, or document why elevated privileges are required.\",\r\n },\r\n {\r\n name: \"CHMOD_DANGEROUS\",\r\n pattern: /chmod\\s+(?:777|a\\+[rwx]|[+]s)/gi,\r\n severity: \"medium\",\r\n category: \"privilege_escalation\",\r\n title: \"Dangerous file permissions\",\r\n description: \"Sets overly permissive file permissions (777) or setuid/setgid bits.\",\r\n codeOnly: true,\r\n fix: \"Use least-privilege permissions (e.g., `chmod 755` or `chmod 644`) instead of 777.\",\r\n },\r\n {\r\n name: \"PATH_TRAVERSAL\",\r\n pattern: /\\.\\.\\//g,\r\n severity: \"medium\",\r\n category: \"file_system\",\r\n title: \"Path traversal\",\r\n description: \"Uses relative path traversal (../) which could access files outside expected directories.\",\r\n fix: \"Use absolute paths or paths relative to the skill's working directory.\",\r\n },\r\n\r\n // ═══════════════════════════════════════════════════════\r\n // LOW: Suspicious but not necessarily malicious\r\n // ═══════════════════════════════════════════════════════\r\n {\r\n name: \"SHELL_EXEC\",\r\n pattern: re([\"child_\", \"process|ex\", \"ec\\\\(|spa\", \"wn\\\\(\"], \"gi\"),\r\n severity: \"low\",\r\n category: \"code_execution\",\r\n title: \"Shell execution API\",\r\n description: \"Uses shell execution APIs — legitimate but worth noting.\",\r\n codeOnly: true,\r\n fix: \"If shell execution is needed, use execFile() with explicit arguments instead of exec() with string commands.\",\r\n },\r\n {\r\n name: \"NETWORK_REQUEST\",\r\n pattern: /fetch\\(|axios|node-fetch|got\\(/gi,\r\n severity: \"low\",\r\n category: \"network\",\r\n title: \"Network request API\",\r\n description: \"Makes network requests — legitimate but worth reviewing targets.\",\r\n codeOnly: true,\r\n fix: \"Document all network endpoints in the skill description so users can review them.\",\r\n },\r\n {\r\n name: \"FILE_WRITE\",\r\n pattern: /fs\\.write|writeFileSync/gi,\r\n severity: \"low\",\r\n category: \"file_system\",\r\n title: \"File write operation\",\r\n description: \"Writes to the filesystem — check what files are being modified.\",\r\n codeOnly: true,\r\n fix: \"Document which files are written and why in the skill description.\",\r\n },\r\n {\r\n name: \"ENV_MODIFICATION\",\r\n pattern: /process\\.env\\[|export\\s+[A-Z_]+=|setenv/gi,\r\n severity: \"low\",\r\n category: \"environment\",\r\n title: \"Environment variable modification\",\r\n description: \"Modifies environment variables which could affect other tools or processes.\",\r\n codeOnly: true,\r\n fix: \"Document env var modifications in the skill description and declare them in requires.env.\",\r\n },\r\n {\r\n name: \"WILDCARD_FILE_ACCESS\",\r\n pattern: /\\*\\.(pem|key|p12|pfx|jks|keystore|ovpn|rdp)/gi,\r\n severity: \"low\",\r\n category: \"credential_theft\",\r\n title: \"Sensitive file extension glob\",\r\n description: \"Globs for files with sensitive extensions (keys, certificates, VPN configs).\",\r\n fix: \"Reference specific files by name instead of using wildcard patterns on sensitive extensions.\",\r\n },\r\n {\r\n name: \"LARGE_BASE64_LITERAL\",\r\n pattern: /[A-Za-z0-9+/=]{100,}/g,\r\n severity: \"low\",\r\n category: \"obfuscation\",\r\n title: \"Large base64-like string\",\r\n description: \"Contains a long base64-like string that may be an encoded payload.\",\r\n fix: \"Include the decoded content directly or explain what the base64 string contains.\",\r\n },\r\n];\r\n\r\nexport const POPULAR_SKILLS = [\r\n \"todoist-cli\",\r\n \"github-manager\",\r\n \"slack-assistant\",\r\n \"email-composer\",\r\n \"calendar-sync\",\r\n \"weather-forecast\",\r\n \"news-reader\",\r\n \"code-reviewer\",\r\n \"docker-helper\",\r\n \"aws-manager\",\r\n \"notion-sync\",\r\n \"jira-tracker\",\r\n \"spotify-controller\",\r\n \"home-assistant\",\r\n \"file-organizer\",\r\n \"pdf-reader\",\r\n \"translate-text\",\r\n \"image-generator\",\r\n \"web-scraper\",\r\n \"database-query\",\r\n \"git-assistant\",\r\n \"linux-admin\",\r\n \"python-helper\",\r\n \"react-builder\",\r\n \"api-tester\",\r\n \"markdown-editor\",\r\n \"csv-analyzer\",\r\n \"ssh-manager\",\r\n \"cron-scheduler\",\r\n \"log-analyzer\",\r\n];\r\n","import { parse as parseYaml } from \"yaml\";\r\nimport type { ParsedSkill, SkillFrontmatter, CodeBlock } from \"../types.js\";\r\n\r\nconst FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\r\nconst CODE_BLOCK_RE = /```(\\w*)\\r?\\n([\\s\\S]*?)```/g;\r\nconst URL_RE = /https?:\\/\\/[^\\s\"'<>\\])+]+/gi;\r\nconst IP_RE = /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g;\r\nconst DOMAIN_RE = /\\b(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,}\\b/gi;\r\n\r\nexport function parseSkill(content: string): ParsedSkill {\r\n let frontmatter: SkillFrontmatter = {};\r\n let body = content;\r\n\r\n const fmMatch = content.match(FRONTMATTER_RE);\r\n if (fmMatch) {\r\n try {\r\n frontmatter = parseYaml(fmMatch[1]) as SkillFrontmatter;\r\n } catch {\r\n frontmatter = {};\r\n }\r\n body = content.slice(fmMatch[0].length).trim();\r\n }\r\n\r\n const codeBlocks: CodeBlock[] = [];\r\n let match: RegExpExecArray | null;\r\n const cbRe = new RegExp(CODE_BLOCK_RE.source, CODE_BLOCK_RE.flags);\r\n\r\n while ((match = cbRe.exec(content)) !== null) {\r\n const before = content.slice(0, match.index);\r\n const lineStart = before.split(\"\\n\").length;\r\n const blockLines = match[0].split(\"\\n\").length;\r\n codeBlocks.push({\r\n language: match[1] || \"unknown\",\r\n content: match[2],\r\n lineStart,\r\n lineEnd: lineStart + blockLines - 1,\r\n });\r\n }\r\n\r\n const urls = [...new Set(content.match(URL_RE) || [])];\r\n const ipAddresses = [...new Set(content.match(IP_RE) || [])];\r\n const domains = [...new Set(content.match(DOMAIN_RE) || [])];\r\n\r\n return {\r\n frontmatter,\r\n body,\r\n codeBlocks,\r\n urls,\r\n ipAddresses,\r\n domains,\r\n rawContent: content,\r\n };\r\n}\r\n","import { THREAT_PATTERNS } from \"../patterns.js\";\r\nimport type { Finding, ParsedSkill, Severity } from \"../types.js\";\r\n\r\nfunction isInCodeBlock(lineNumber: number, skill: ParsedSkill): boolean {\r\n return skill.codeBlocks.some(\r\n (block) => lineNumber >= block.lineStart && lineNumber <= block.lineEnd\r\n );\r\n}\r\n\r\nfunction isInHeading(lineNumber: number, rawContent: string): boolean {\r\n const lines = rawContent.split(\"\\n\");\r\n const line = lines[lineNumber - 1] || \"\";\r\n return /^\\s*#{1,6}\\s/.test(line);\r\n}\r\n\r\nconst BASE_CONFIDENCE: Record<Severity, number> = {\r\n critical: 0.9,\r\n high: 0.8,\r\n medium: 0.6,\r\n low: 0.5,\r\n};\r\n\r\nexport function runStaticAnalysis(skill: ParsedSkill): Finding[] {\r\n const findings: Finding[] = [];\r\n\r\n for (const threat of THREAT_PATTERNS) {\r\n const re = new RegExp(threat.pattern.source, threat.pattern.flags);\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = re.exec(skill.rawContent)) !== null) {\r\n const before = skill.rawContent.slice(0, match.index);\r\n const lineNumber = before.split(\"\\n\").length;\r\n\r\n if (threat.codeOnly && !isInCodeBlock(lineNumber, skill)) {\r\n continue;\r\n }\r\n\r\n const inCode = isInCodeBlock(lineNumber, skill);\r\n const inHeading = isInHeading(lineNumber, skill.rawContent);\r\n\r\n let contextMultiplier: number;\r\n if (inCode && threat.codeOnly) {\r\n contextMultiplier = 1.0;\r\n } else if (inCode) {\r\n contextMultiplier = 0.95;\r\n } else if (inHeading) {\r\n contextMultiplier = 0.5;\r\n } else if (threat.codeOnly) {\r\n // codeOnly pattern somehow in prose (shouldn't happen due to skip above)\r\n contextMultiplier = 0.4;\r\n } else {\r\n // Non-codeOnly patterns are designed to match in prose\r\n contextMultiplier = 0.9;\r\n }\r\n\r\n const baseConfidence = BASE_CONFIDENCE[threat.severity];\r\n const confidence = Math.min(1.0, baseConfidence * contextMultiplier);\r\n\r\n findings.push({\r\n category: threat.category,\r\n severity: threat.severity,\r\n title: threat.title,\r\n description: threat.description,\r\n evidence: match[0],\r\n lineNumber,\r\n analysisPass: \"static-analysis\",\r\n confidence: Math.round(confidence * 100) / 100,\r\n fix: threat.fix,\r\n });\r\n }\r\n }\r\n\r\n return findings;\r\n}\r\n","import type { Finding, ParsedSkill } from \"../types.js\";\r\n\r\nconst SEMVER_RE = /^\\d+\\.\\d+\\.\\d+/;\r\n\r\nconst KNOWN_BINS = [\r\n \"curl\", \"wget\", \"git\", \"python\", \"python3\", \"node\", \"npm\", \"npx\",\r\n \"brew\", \"apt\", \"pip\", \"docker\", \"kubectl\", \"ssh\", \"scp\", \"rsync\",\r\n \"ffmpeg\", \"jq\", \"sed\", \"awk\", \"grep\", \"find\",\r\n];\r\n\r\nexport function validateMetadata(skill: ParsedSkill): Finding[] {\r\n const findings: Finding[] = [];\r\n const fm = skill.frontmatter;\r\n const pass = \"metadata-validator\";\r\n\r\n if (!fm.name) {\r\n findings.push({\r\n category: \"metadata\",\r\n severity: \"medium\",\r\n title: \"Missing skill name\",\r\n description: \"SKILL.md frontmatter does not declare a name.\",\r\n analysisPass: pass,\r\n fix: \"Add `name:` to the YAML frontmatter.\",\r\n });\r\n }\r\n\r\n if (!fm.description) {\r\n findings.push({\r\n category: \"metadata\",\r\n severity: \"medium\",\r\n title: \"Missing description\",\r\n description: \"SKILL.md frontmatter does not declare a description.\",\r\n analysisPass: pass,\r\n fix: \"Add `description:` to the YAML frontmatter.\",\r\n });\r\n } else if (fm.description.length < 10) {\r\n findings.push({\r\n category: \"metadata\",\r\n severity: \"low\",\r\n title: \"Vague description\",\r\n description: \"Skill description is suspiciously short.\",\r\n evidence: fm.description,\r\n analysisPass: pass,\r\n fix: \"Write a more detailed description (at least 10 characters).\",\r\n });\r\n }\r\n\r\n if (fm.version && !SEMVER_RE.test(fm.version)) {\r\n findings.push({\r\n category: \"metadata\",\r\n severity: \"low\",\r\n title: \"Invalid version format\",\r\n description: \"Version does not follow semver format.\",\r\n evidence: fm.version,\r\n analysisPass: pass,\r\n fix: \"Use semver format: `version: X.Y.Z` (e.g., `1.0.0`).\",\r\n });\r\n }\r\n\r\n const declaredBins = new Set(fm.metadata?.openclaw?.requires?.bins || []);\r\n\r\n for (const bin of KNOWN_BINS) {\r\n const binRe = new RegExp(`\\\\b${bin}\\\\b`, \"i\");\r\n if (binRe.test(skill.rawContent) && !declaredBins.has(bin)) {\r\n const usedInCode = skill.codeBlocks.some((cb) => binRe.test(cb.content));\r\n if (usedInCode) {\r\n findings.push({\r\n category: \"metadata\",\r\n severity: \"low\",\r\n title: `Undeclared binary: ${bin}`,\r\n description: `Skill uses '${bin}' in code but does not declare it in requires.bins.`,\r\n analysisPass: pass,\r\n fix: `Add '${bin}' to \\`metadata.openclaw.requires.bins\\` in frontmatter.`,\r\n });\r\n }\r\n }\r\n }\r\n\r\n const declaredEnv = new Set(fm.metadata?.openclaw?.requires?.env || []);\r\n const envRe = /\\$\\{?([A-Z][A-Z0-9_]+)\\}?/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = envRe.exec(skill.rawContent)) !== null) {\r\n const envVar = match[1];\r\n if (!declaredEnv.has(envVar) && envVar.length > 2) {\r\n findings.push({\r\n category: \"metadata\",\r\n severity: \"low\",\r\n title: `Undeclared env var: ${envVar}`,\r\n description: `References environment variable $${envVar} but does not declare it in requires.env.`,\r\n evidence: match[0],\r\n analysisPass: pass,\r\n fix: `Add '${envVar}' to \\`metadata.openclaw.requires.env\\` in frontmatter.`,\r\n });\r\n }\r\n }\r\n\r\n return findings;\r\n}\r\n","import type { Finding, ParsedSkill } from \"../types.js\";\r\n\r\nconst NPX_AUTO_INSTALL_RE = /npx\\s+-y\\s+/gi;\r\nconst NPM_INSTALL_RE = /npm\\s+install\\s+(-g\\s+)?(\\S+)/gi;\r\n\r\nexport function checkDependencies(skill: ParsedSkill): Finding[] {\r\n const findings: Finding[] = [];\r\n const pass = \"dependency-checker\";\r\n\r\n let match: RegExpExecArray | null;\r\n const npxRe = new RegExp(NPX_AUTO_INSTALL_RE.source, NPX_AUTO_INSTALL_RE.flags);\r\n\r\n while ((match = npxRe.exec(skill.rawContent)) !== null) {\r\n const before = skill.rawContent.slice(0, match.index);\r\n const lineNumber = before.split(\"\\n\").length;\r\n\r\n findings.push({\r\n category: \"dependency_risk\",\r\n severity: \"medium\",\r\n title: \"npx auto-install (-y flag)\",\r\n description: \"Uses 'npx -y' which auto-installs packages without user confirmation.\",\r\n evidence: match[0],\r\n lineNumber,\r\n analysisPass: pass,\r\n fix: \"Remove the `-y` flag from npx to require user confirmation before installing.\",\r\n });\r\n }\r\n\r\n const npmRe = new RegExp(NPM_INSTALL_RE.source, NPM_INSTALL_RE.flags);\r\n while ((match = npmRe.exec(skill.rawContent)) !== null) {\r\n if (match[1]) {\r\n findings.push({\r\n category: \"dependency_risk\",\r\n severity: \"medium\",\r\n title: \"Global npm package install\",\r\n description: `Installs npm package globally: ${match[2]}`,\r\n evidence: match[0],\r\n analysisPass: pass,\r\n fix: \"Use a local install (`npm install` without `-g`) or declare the dependency in requires.bins.\",\r\n });\r\n }\r\n }\r\n\r\n return findings;\r\n}\r\n","import { distance } from \"fastest-levenshtein\";\r\nimport { POPULAR_SKILLS } from \"../patterns.js\";\r\nimport type { Finding } from \"../types.js\";\r\n\r\nconst MAX_EDIT_DISTANCE = 2;\r\n\r\nexport function detectTyposquats(skillName: string): Finding[] {\r\n if (!skillName) return [];\r\n\r\n const findings: Finding[] = [];\r\n const normalized = skillName.toLowerCase().trim();\r\n\r\n for (const popular of POPULAR_SKILLS) {\r\n if (normalized === popular) continue;\r\n\r\n const d = distance(normalized, popular);\r\n if (d > 0 && d <= MAX_EDIT_DISTANCE) {\r\n findings.push({\r\n category: \"typosquatting\",\r\n severity: \"high\",\r\n title: `Possible typosquat of \"${popular}\"`,\r\n description: `Skill name \"${skillName}\" is ${d} edit(s) away from popular skill \"${popular}\". This may be an attempt to impersonate a trusted skill.`,\r\n evidence: `\"${skillName}\" ≈ \"${popular}\" (distance: ${d})`,\r\n analysisPass: \"typosquat-detector\",\r\n });\r\n }\r\n }\r\n\r\n const patterns = [\r\n { re: /-{2,}/, desc: \"extra hyphens\" },\r\n { re: /(.)\\1{2,}/, desc: \"repeated characters\" },\r\n ];\r\n\r\n for (const p of patterns) {\r\n if (p.re.test(normalized) && !POPULAR_SKILLS.includes(normalized)) {\r\n findings.push({\r\n category: \"typosquatting\",\r\n severity: \"medium\",\r\n title: `Suspicious naming pattern: ${p.desc}`,\r\n description: `Skill name \"${skillName}\" has ${p.desc}, which is a common typosquatting technique.`,\r\n analysisPass: \"typosquat-detector\",\r\n });\r\n }\r\n }\r\n\r\n return findings;\r\n}\r\n","import type { Finding, FindingsCount, RiskGrade } from \"../types.js\";\r\n\r\nconst SEVERITY_WEIGHTS = {\r\n critical: 30,\r\n high: 15,\r\n medium: 7,\r\n low: 3,\r\n} as const;\r\n\r\nexport function calculateRiskScore(findings: Finding[]): number {\r\n let score = 0;\r\n for (const f of findings) {\r\n score += SEVERITY_WEIGHTS[f.severity] * (f.confidence ?? 1.0);\r\n }\r\n return Math.min(score, 100);\r\n}\r\n\r\nexport function getRiskGrade(score: number): RiskGrade {\r\n if (score <= 10) return \"A\";\r\n if (score <= 25) return \"B\";\r\n if (score <= 50) return \"C\";\r\n if (score <= 75) return \"D\";\r\n return \"F\";\r\n}\r\n\r\nexport function countFindings(findings: Finding[]): FindingsCount {\r\n const counts: FindingsCount = { critical: 0, high: 0, medium: 0, low: 0 };\r\n for (const f of findings) {\r\n counts[f.severity]++;\r\n }\r\n return counts;\r\n}\r\n","import { createHash } from \"node:crypto\";\r\nimport type { ScanResult } from \"../types.js\";\r\n\r\nconst MAX_ENTRIES = 100;\r\nconst cache = new Map<string, ScanResult>();\r\n\r\nfunction hashContent(content: string): string {\r\n return createHash(\"sha256\").update(content).digest(\"hex\");\r\n}\r\n\r\nexport function getCached(content: string): ScanResult | undefined {\r\n const key = hashContent(content);\r\n const result = cache.get(key);\r\n if (result) {\r\n // Move to end (most recently used)\r\n cache.delete(key);\r\n cache.set(key, result);\r\n }\r\n return result;\r\n}\r\n\r\nexport function setCached(content: string, result: ScanResult): void {\r\n const key = hashContent(content);\r\n if (cache.has(key)) {\r\n cache.delete(key);\r\n } else if (cache.size >= MAX_ENTRIES) {\r\n // Evict oldest (first entry)\r\n const oldest = cache.keys().next().value!;\r\n cache.delete(oldest);\r\n }\r\n cache.set(key, result);\r\n}\r\n","import type { Finding, ScanResult } from \"../types.js\";\r\nimport { parseSkill } from \"./skill-parser.js\";\r\nimport { runStaticAnalysis } from \"./static-analysis.js\";\r\nimport { validateMetadata } from \"./metadata-validator.js\";\r\nimport { checkDependencies } from \"./dependency-checker.js\";\r\nimport { detectTyposquats } from \"./typosquat-detector.js\";\r\nimport { calculateRiskScore, getRiskGrade, countFindings } from \"./risk-scorer.js\";\r\nimport { getCached, setCached } from \"./cache.js\";\r\n\r\nexport interface ScanOptions {\r\n semantic?: boolean;\r\n semanticAnalyzer?: (content: string) => Promise<Finding[]>;\r\n ignorePatterns?: string[];\r\n skipCache?: boolean;\r\n}\r\n\r\nexport async function scanSkill(\r\n content: string,\r\n options: ScanOptions = {}\r\n): Promise<ScanResult> {\r\n if (!options.skipCache) {\r\n const cached = getCached(content);\r\n if (cached) {\r\n return { ...cached, cached: true };\r\n }\r\n }\r\n\r\n const skill = parseSkill(content);\r\n const allFindings: Finding[] = [];\r\n\r\n allFindings.push(...runStaticAnalysis(skill));\r\n allFindings.push(...validateMetadata(skill));\r\n\r\n if (options.semantic && options.semanticAnalyzer) {\r\n const semanticFindings = await options.semanticAnalyzer(content);\r\n allFindings.push(...semanticFindings);\r\n }\r\n\r\n allFindings.push(...checkDependencies(skill));\r\n\r\n if (skill.frontmatter.name) {\r\n allFindings.push(...detectTyposquats(skill.frontmatter.name));\r\n }\r\n\r\n // Filter out ignored patterns\r\n const filteredFindings = options.ignorePatterns?.length\r\n ? allFindings.filter(\r\n (f) => !options.ignorePatterns!.some((ig) => f.title === ig || f.category === ig)\r\n )\r\n : allFindings;\r\n\r\n const riskScore = calculateRiskScore(filteredFindings);\r\n const riskGrade = getRiskGrade(riskScore);\r\n const findingsCount = countFindings(filteredFindings);\r\n\r\n const recommendation =\r\n riskScore >= 76 ? \"block\" : riskScore >= 26 ? \"warn\" : \"approve\";\r\n\r\n const result: ScanResult = {\r\n skillName: skill.frontmatter.name || \"unknown\",\r\n skillVersion: skill.frontmatter.version,\r\n skillSource: \"local\",\r\n status: \"complete\",\r\n riskScore,\r\n riskGrade,\r\n findingsCount,\r\n findings: filteredFindings,\r\n recommendation,\r\n };\r\n\r\n if (!options.skipCache) {\r\n setCached(content, result);\r\n }\r\n\r\n return result;\r\n}\r\n\r\nexport { parseSkill } from \"./skill-parser.js\";\r\nexport { runStaticAnalysis } from \"./static-analysis.js\";\r\nexport { validateMetadata } from \"./metadata-validator.js\";\r\nexport { checkDependencies } from \"./dependency-checker.js\";\r\nexport { detectTyposquats } from \"./typosquat-detector.js\";\r\nexport { calculateRiskScore, getRiskGrade, countFindings } from \"./risk-scorer.js\";\r\n","import chalk from \"chalk\";\r\nimport type { ScanResult, Finding, Severity } from \"@clawvet/shared\";\r\n\r\nconst SEVERITY_COLORS: Record<Severity, (s: string) => string> = {\r\n critical: chalk.bgRed.white.bold,\r\n high: chalk.red.bold,\r\n medium: chalk.yellow,\r\n low: chalk.blue,\r\n};\r\n\r\nconst GRADE_COLORS: Record<string, (s: string) => string> = {\r\n A: chalk.green.bold,\r\n B: chalk.greenBright,\r\n C: chalk.yellow.bold,\r\n D: chalk.redBright.bold,\r\n F: chalk.bgRed.white.bold,\r\n};\r\n\r\nexport function printScanResult(result: ScanResult): void {\r\n console.log();\r\n console.log(chalk.bold(\"━\".repeat(60)));\r\n console.log(chalk.bold(\" ClawVet Scan Report\"));\r\n console.log(chalk.bold(\"━\".repeat(60)));\r\n console.log();\r\n\r\n console.log(` Skill: ${chalk.bold(result.skillName)}`);\r\n if (result.skillVersion) {\r\n console.log(` Version: ${result.skillVersion}`);\r\n }\r\n console.log();\r\n\r\n // Risk score\r\n const gradeColor = GRADE_COLORS[result.riskGrade] || chalk.white;\r\n console.log(\r\n ` Risk Score: ${gradeColor(`${result.riskScore}/100`)} Grade: ${gradeColor(result.riskGrade)}`\r\n );\r\n console.log();\r\n\r\n // Findings summary\r\n const fc = result.findingsCount;\r\n console.log(\" Findings:\");\r\n if (fc.critical)\r\n console.log(\r\n ` ${SEVERITY_COLORS.critical(` CRITICAL `)} ${fc.critical}`\r\n );\r\n if (fc.high)\r\n console.log(` ${SEVERITY_COLORS.high(\"HIGH\")} ${fc.high}`);\r\n if (fc.medium)\r\n console.log(` ${SEVERITY_COLORS.medium(\"MEDIUM\")} ${fc.medium}`);\r\n if (fc.low) console.log(` ${SEVERITY_COLORS.low(\"LOW\")} ${fc.low}`);\r\n if (!fc.critical && !fc.high && !fc.medium && !fc.low) {\r\n console.log(` ${chalk.green(\"No findings — skill looks clean!\")}`);\r\n }\r\n console.log();\r\n\r\n // Detailed findings\r\n if (result.findings.length > 0) {\r\n console.log(chalk.bold(\" Details:\"));\r\n console.log();\r\n for (const f of result.findings) {\r\n const color = SEVERITY_COLORS[f.severity];\r\n const confStr = f.confidence != null ? ` ${Math.round(f.confidence * 100)}%` : \"\";\r\n console.log(` ${color(`[${f.severity.toUpperCase()}${confStr}]`)} ${f.title}`);\r\n console.log(` ${chalk.dim(f.description)}`);\r\n if (f.evidence) {\r\n console.log(` Evidence: ${chalk.italic(f.evidence)}`);\r\n }\r\n if (f.lineNumber) {\r\n console.log(` Line: ${f.lineNumber}`);\r\n }\r\n if (f.fix) {\r\n console.log(` Fix: ${chalk.green(f.fix)}`);\r\n }\r\n console.log();\r\n }\r\n }\r\n\r\n // Recommendation\r\n const recColors: Record<string, (s: string) => string> = {\r\n block: chalk.bgRed.white.bold,\r\n warn: chalk.bgYellow.black.bold,\r\n approve: chalk.bgGreen.black.bold,\r\n };\r\n const rec = result.recommendation || \"approve\";\r\n console.log(\r\n ` Recommendation: ${(recColors[rec] || chalk.white)(` ${rec.toUpperCase()} `)}`\r\n );\r\n console.log();\r\n console.log(chalk.bold(\"━\".repeat(60)));\r\n console.log();\r\n}\r\n","import type { ScanResult } from \"@clawvet/shared\";\r\n\r\nexport function printJsonResult(result: ScanResult): void {\r\n console.log(JSON.stringify(result, null, 2));\r\n}\r\n","import type { ScanResult, Finding, Severity } from \"@clawvet/shared\";\r\n\r\nconst SEVERITY_TO_SARIF: Record<Severity, string> = {\r\n critical: \"error\",\r\n high: \"error\",\r\n medium: \"warning\",\r\n low: \"note\",\r\n};\r\n\r\nconst SEVERITY_TO_LEVEL: Record<Severity, string> = {\r\n critical: \"9.0\",\r\n high: \"7.0\",\r\n medium: \"4.0\",\r\n low: \"1.0\",\r\n};\r\n\r\nexport function printSarifResult(result: ScanResult): void {\r\n const rules = new Map<string, { id: string; finding: Finding }>();\r\n\r\n for (const f of result.findings) {\r\n const ruleId = f.category + \"/\" + f.title.toLowerCase().replace(/[^a-z0-9]+/g, \"-\");\r\n if (!rules.has(ruleId)) {\r\n rules.set(ruleId, { id: ruleId, finding: f });\r\n }\r\n }\r\n\r\n const sarif = {\r\n $schema: \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json\",\r\n version: \"2.1.0\",\r\n runs: [\r\n {\r\n tool: {\r\n driver: {\r\n name: \"clawvet\",\r\n informationUri: \"https://github.com/clawvet/clawvet\",\r\n rules: [...rules.values()].map((r) => ({\r\n id: r.id,\r\n shortDescription: { text: r.finding.title },\r\n fullDescription: { text: r.finding.description },\r\n defaultConfiguration: {\r\n level: SEVERITY_TO_SARIF[r.finding.severity],\r\n },\r\n properties: {\r\n security_severity: SEVERITY_TO_LEVEL[r.finding.severity],\r\n },\r\n })),\r\n },\r\n },\r\n results: result.findings.map((f) => {\r\n const ruleId = f.category + \"/\" + f.title.toLowerCase().replace(/[^a-z0-9]+/g, \"-\");\r\n return {\r\n ruleId,\r\n level: SEVERITY_TO_SARIF[f.severity],\r\n message: {\r\n text: f.description + (f.evidence ? ` Evidence: ${f.evidence}` : \"\"),\r\n ...(f.fix ? { markdown: `${f.description}\\n\\n**Fix:** ${f.fix}` } : {}),\r\n },\r\n locations: [\r\n {\r\n physicalLocation: {\r\n artifactLocation: { uri: \"SKILL.md\" },\r\n region: { startLine: f.lineNumber ?? 1 },\r\n },\r\n },\r\n ],\r\n };\r\n }),\r\n },\r\n ],\r\n };\r\n\r\n console.log(JSON.stringify(sarif, null, 2));\r\n}\r\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { homedir, platform, release } from \"node:os\";\r\nimport { randomUUID } from \"node:crypto\";\r\nimport type { ScanResult } from \"@clawvet/shared\";\r\n\r\nconst CONFIG_DIR = join(homedir(), \".clawvet\");\r\nconst CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\r\nconst TELEMETRY_ENDPOINT = \"https://bazzzz--0ab7a9301f3911f1ab9942dde27851f2.web.val.run\";\r\n\r\ninterface Config {\r\n telemetry?: \"on\" | \"off\" | undefined; // undefined = not yet asked\r\n deviceId?: string;\r\n scanCount?: number;\r\n}\r\n\r\nfunction loadConfig(): Config {\r\n try {\r\n if (existsSync(CONFIG_FILE)) {\r\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf-8\"));\r\n }\r\n } catch {\r\n // corrupted config, start fresh\r\n }\r\n return {};\r\n}\r\n\r\nfunction saveConfig(config: Config): void {\r\n try {\r\n mkdirSync(CONFIG_DIR, { recursive: true });\r\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\r\n } catch {\r\n // non-critical, ignore\r\n }\r\n}\r\n\r\nexport function isTelemetryEnabled(): boolean {\r\n const env = process.env.CLAWVET_TELEMETRY;\r\n if (env === \"0\" || env === \"off\") return false;\r\n if (env === \"1\" || env === \"on\") return true;\r\n const config = loadConfig();\r\n return config.telemetry === \"on\";\r\n}\r\n\r\nexport function setTelemetry(enabled: boolean): void {\r\n const config = loadConfig();\r\n config.telemetry = enabled ? \"on\" : \"off\";\r\n saveConfig(config);\r\n}\r\n\r\nexport function hasBeenAsked(): boolean {\r\n const config = loadConfig();\r\n return config.telemetry !== undefined;\r\n}\r\n\r\nfunction getDeviceId(): string {\r\n const config = loadConfig();\r\n if (!config.deviceId) {\r\n config.deviceId = randomUUID();\r\n saveConfig(config);\r\n }\r\n return config.deviceId;\r\n}\r\n\r\nfunction incrementScanCount(): number {\r\n const config = loadConfig();\r\n config.scanCount = (config.scanCount || 0) + 1;\r\n saveConfig(config);\r\n return config.scanCount;\r\n}\r\n\r\nexport function sendTelemetry(result: ScanResult): void {\r\n if (!isTelemetryEnabled()) return;\r\n\r\n const scanCount = incrementScanCount();\r\n\r\n const payload = {\r\n deviceId: getDeviceId(),\r\n scanCount,\r\n ts: new Date().toISOString(),\r\n os: platform(),\r\n osVersion: release(),\r\n skillName: result.skillName,\r\n riskScore: result.riskScore,\r\n riskGrade: result.riskGrade,\r\n findingsCount: result.findingsCount,\r\n cached: result.cached ?? false,\r\n };\r\n\r\n // Fire-and-forget — never block the CLI\r\n fetch(TELEMETRY_ENDPOINT, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify(payload),\r\n signal: AbortSignal.timeout(3000),\r\n }).catch(() => {\r\n // silently ignore — telemetry is best-effort\r\n });\r\n}\r\n","import { readdirSync, existsSync, readFileSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { homedir } from \"node:os\";\r\nimport { scanSkill } from \"@clawvet/shared\";\r\nimport { printScanResult } from \"../output/terminal.js\";\r\nimport chalk from \"chalk\";\r\n\r\nconst DEFAULT_SKILL_DIRS = [\r\n join(homedir(), \".openclaw\", \"skills\"),\r\n join(homedir(), \".openclaw\", \"workspace\", \"skills\"),\r\n];\r\n\r\nexport async function auditCommand(options: { dir?: string } = {}): Promise<void> {\r\n const SKILL_DIRS = options.dir ? [options.dir] : DEFAULT_SKILL_DIRS;\r\n console.log(chalk.bold(\"\\nClawVet Audit — Scanning all installed skills\\n\"));\r\n\r\n let totalScanned = 0;\r\n let totalThreats = 0;\r\n\r\n for (const dir of SKILL_DIRS) {\r\n if (!existsSync(dir)) {\r\n if (options.dir) {\r\n console.error(chalk.yellow(`Warning: Directory not found: ${dir}\\n`));\r\n process.exit(1);\r\n }\r\n continue;\r\n }\r\n\r\n // If the dir itself contains a SKILL.md, scan it directly\r\n const directSkillFile = join(dir, \"SKILL.md\");\r\n if (existsSync(directSkillFile)) {\r\n const content = readFileSync(directSkillFile, \"utf-8\");\r\n const result = await scanSkill(content);\r\n totalScanned++;\r\n totalThreats += result.findings.length;\r\n printScanResult(result);\r\n continue;\r\n }\r\n\r\n const entries = readdirSync(dir, { withFileTypes: true });\r\n for (const entry of entries) {\r\n if (!entry.isDirectory()) continue;\r\n const skillFile = join(dir, entry.name, \"SKILL.md\");\r\n if (!existsSync(skillFile)) continue;\r\n\r\n const content = readFileSync(skillFile, \"utf-8\");\r\n const result = await scanSkill(content);\r\n totalScanned++;\r\n totalThreats += result.findings.length;\r\n\r\n printScanResult(result);\r\n }\r\n }\r\n\r\n console.log(chalk.bold(`\\nAudit complete: ${totalScanned} skills scanned, ${totalThreats} findings\\n`));\r\n}\r\n","import { readFileSync, existsSync, watch } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { homedir } from \"node:os\";\r\nimport chalk from \"chalk\";\r\nimport { scanSkill } from \"@clawvet/shared\";\r\nimport { printScanResult } from \"../output/terminal.js\";\r\n\r\nconst DEFAULT_SKILL_DIRS = [\r\n join(homedir(), \".openclaw\", \"skills\"),\r\n join(homedir(), \".openclaw\", \"workspace\", \"skills\"),\r\n];\r\n\r\nexport async function watchCommand(options: {\r\n threshold?: number;\r\n dir?: string;\r\n}): Promise<void> {\r\n const threshold = options.threshold || 50;\r\n const SKILL_DIRS = options.dir ? [options.dir] : DEFAULT_SKILL_DIRS;\r\n console.log(\r\n chalk.bold(\r\n `\\nClawVet Watch — monitoring skill directories (threshold: ${threshold})\\n`\r\n )\r\n );\r\n\r\n const watchDirs: string[] = [];\r\n for (const dir of SKILL_DIRS) {\r\n if (existsSync(dir)) {\r\n watchDirs.push(dir);\r\n }\r\n }\r\n\r\n if (watchDirs.length === 0) {\r\n console.log(\r\n chalk.yellow(\r\n \"No OpenClaw skill directories found. Watching will start when directories are created.\\n\"\r\n )\r\n );\r\n console.log(chalk.dim(\"Expected directories:\"));\r\n for (const dir of SKILL_DIRS) {\r\n console.log(chalk.dim(` ${dir}`));\r\n }\r\n console.log();\r\n process.exit(1);\r\n }\r\n\r\n console.log(chalk.dim(\"Watching:\"));\r\n for (const dir of watchDirs) {\r\n console.log(chalk.dim(` ${dir}`));\r\n }\r\n console.log();\r\n\r\n for (const dir of watchDirs) {\r\n const watcher = watch(dir, { recursive: true }, async (event, filename) => {\r\n if (!filename?.endsWith(\"SKILL.md\")) return;\r\n\r\n const skillFile = join(dir, filename);\r\n if (!existsSync(skillFile)) return;\r\n\r\n console.log(chalk.dim(`\\nDetected change: ${filename}`));\r\n\r\n try {\r\n const content = readFileSync(skillFile, \"utf-8\");\r\n const result = await scanSkill(content);\r\n\r\n if (result.cached) {\r\n console.log(chalk.dim(\"(cached)\"));\r\n }\r\n printScanResult(result);\r\n\r\n if (result.riskScore > threshold) {\r\n console.log(\r\n chalk.bgRed.white.bold(\r\n ` BLOCKED — Risk score ${result.riskScore} exceeds threshold ${threshold} `\r\n )\r\n );\r\n console.log(\r\n chalk.red(\r\n `This skill should not be installed. Run 'clawvet scan ${skillFile}' for details.\\n`\r\n )\r\n );\r\n }\r\n } catch (err) {\r\n console.error(chalk.red(`Error scanning ${filename}:`), err);\r\n }\r\n });\r\n\r\n process.on(\"SIGINT\", () => {\r\n watcher.close();\r\n console.log(chalk.dim(\"\\nWatch stopped.\"));\r\n process.exit(0);\r\n });\r\n }\r\n\r\n console.log(chalk.dim(\"Press Ctrl+C to stop watching.\\n\"));\r\n await new Promise(() => {});\r\n}\r\n","import { readFileSync, existsSync, statSync } from \"node:fs\";\r\nimport { resolve, join } from \"node:path\";\r\nimport chalk from \"chalk\";\r\nimport { scanSkill } from \"@clawvet/shared\";\r\nimport type { RiskGrade } from \"@clawvet/shared\";\r\n\r\nconst GRADE_COLORS: Record<RiskGrade, string> = {\r\n A: \"brightgreen\",\r\n B: \"green\",\r\n C: \"yellow\",\r\n D: \"orange\",\r\n F: \"red\",\r\n};\r\n\r\nconst GRADE_LABELS: Record<RiskGrade, string> = {\r\n A: \"safe\",\r\n B: \"safe\",\r\n C: \"review\",\r\n D: \"risky\",\r\n F: \"dangerous\",\r\n};\r\n\r\nexport async function badgeCommand(\r\n target: string,\r\n options: { markdown?: boolean }\r\n): Promise<void> {\r\n const skillPath = resolve(target);\r\n let skillFile = skillPath;\r\n\r\n if (\r\n existsSync(skillPath) &&\r\n !skillPath.endsWith(\".md\") &&\r\n existsSync(join(skillPath, \"SKILL.md\"))\r\n ) {\r\n skillFile = join(skillPath, \"SKILL.md\");\r\n }\r\n\r\n if (!existsSync(skillFile) || statSync(skillFile).isDirectory()) {\r\n console.error(`Error: Cannot find SKILL.md at ${skillFile}`);\r\n process.exit(1);\r\n }\r\n\r\n const content = readFileSync(skillFile, \"utf-8\");\r\n const result = await scanSkill(content);\r\n\r\n const label = GRADE_LABELS[result.riskGrade];\r\n const color = GRADE_COLORS[result.riskGrade];\r\n const badgeUrl = `https://img.shields.io/badge/clawvet-${result.riskGrade}%20${label}-${color}`;\r\n const linkUrl = \"https://github.com/MohibShaikh/clawvet\";\r\n\r\n if (options.markdown) {\r\n console.log(`[](${linkUrl})`);\r\n } else {\r\n console.log();\r\n console.log(chalk.bold(\" ClawVet Trust Badge\"));\r\n console.log();\r\n console.log(` Skill: ${chalk.bold(result.skillName)}`);\r\n console.log(` Grade: ${result.riskGrade} (${label})`);\r\n console.log(` Score: ${result.riskScore}/100`);\r\n console.log();\r\n console.log(chalk.dim(\" Markdown (paste in README):\"));\r\n console.log();\r\n console.log(` [](${linkUrl})`);\r\n console.log();\r\n console.log(chalk.dim(\" HTML:\"));\r\n console.log();\r\n console.log(` <a href=\"${linkUrl}\"><img src=\"${badgeUrl}\" alt=\"ClawVet ${result.riskGrade}\"></a>`);\r\n console.log();\r\n }\r\n}\r\n"],"mappings":"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","names":["readFileSync","existsSync","join","chalk","re","existsSync","join","readFileSync","chalk","resolve","existsSync","readFileSync","join","homedir","chalk","join","homedir","existsSync","readFileSync","readFileSync","existsSync","join","homedir","chalk","DEFAULT_SKILL_DIRS","join","homedir","chalk","existsSync","readFileSync","readFileSync","existsSync","statSync","resolve","join","chalk","GRADE_COLORS","resolve","existsSync","join","statSync","readFileSync","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/scan.ts","../../shared/src/patterns.ts","../../shared/src/scanner/skill-parser.ts","../../shared/src/scanner/static-analysis.ts","../../shared/src/scanner/metadata-validator.ts","../../shared/src/scanner/dependency-checker.ts","../../shared/src/scanner/typosquat-detector.ts","../../shared/src/scanner/risk-scorer.ts","../../shared/src/scanner/cache.ts","../../shared/src/scanner/index.ts","../src/output/terminal.ts","../src/output/json.ts","../src/output/sarif.ts","../src/telemetry.ts","../src/commands/audit.ts","../src/commands/watch.ts","../src/commands/badge.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { scanCommand } from \"./commands/scan.js\";\nimport { auditCommand } from \"./commands/audit.js\";\nimport { watchCommand } from \"./commands/watch.js\";\nimport { badgeCommand } from \"./commands/badge.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"clawvet\")\n .description(\"Skill vetting & supply chain security for OpenClaw\")\n .version(\"0.6.0\");\n\nprogram\n .command(\"scan\")\n .description(\"Scan a skill for security threats\")\n .argument(\"<target>\", \"Path to skill folder or SKILL.md file\")\n .option(\"--format <format>\", \"Output format: terminal, json, or sarif\", \"terminal\")\n .option(\"--fail-on <severity>\", \"Exit 1 if findings at this severity or above\")\n .option(\"--semantic\", \"Enable AI semantic analysis (requires ANTHROPIC_API_KEY)\")\n .option(\"--remote\", \"Fetch skill from ClawHub by name instead of local path\")\n .option(\"-q, --quiet\", \"Suppress all output, exit code only (0=pass, 1=fail)\")\n .option(\"--subscribe\", \"Open the ClawVet feedback & alerts form\")\n .action(async (target, opts) => {\n if (opts.subscribe) {\n const url = \"https://tally.so/r/jaMdaa\";\n console.log(`Opening ${url} ...`);\n const { exec } = await import(\"node:child_process\");\n const cmd = process.platform === \"win32\" ? `start ${url}` : process.platform === \"darwin\" ? `open ${url}` : `xdg-open ${url}`;\n exec(cmd);\n }\n await scanCommand(target, {\n format: opts.format,\n failOn: opts.failOn,\n semantic: opts.semantic,\n remote: opts.remote,\n quiet: opts.quiet,\n });\n });\n\nprogram\n .command(\"audit\")\n .description(\"Scan all installed OpenClaw skills\")\n .option(\"--dir <path>\", \"Custom skills directory to scan\")\n .action(async (opts) => {\n await auditCommand({ dir: opts.dir });\n });\n\nprogram\n .command(\"watch\")\n .description(\"Pre-install hook — blocks risky skill installs\")\n .option(\"--threshold <score>\", \"Risk score threshold (default 50)\", \"50\")\n .option(\"--dir <path>\", \"Custom skills directory to watch\")\n .action(async (opts) => {\n await watchCommand({ threshold: parseInt(opts.threshold), dir: opts.dir });\n });\n\nprogram\n .command(\"badge\")\n .description(\"Generate a trust badge for a skill's README\")\n .argument(\"<target>\", \"Path to skill folder or SKILL.md file\")\n .option(\"--md\", \"Output only the markdown snippet\")\n .action(async (target, opts) => {\n await badgeCommand(target, { markdown: opts.md });\n });\n\nprogram\n .command(\"feedback\")\n .description(\"Open the ClawVet feedback & threat alerts form\")\n .action(async () => {\n const url = \"https://tally.so/r/jaMdaa\";\n console.log(`Opening ${url} ...`);\n const { exec } = await import(\"node:child_process\");\n const cmd = process.platform === \"win32\" ? `start ${url}` : process.platform === \"darwin\" ? `open ${url}` : `xdg-open ${url}`;\n exec(cmd);\n });\n\nprogram.parse();\n","import { readFileSync, existsSync, statSync } from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { scanSkill } from \"@clawvet/shared\";\nimport { printScanResult } from \"../output/terminal.js\";\nimport { printJsonResult } from \"../output/json.js\";\nimport { printSarifResult } from \"../output/sarif.js\";\nimport { sendTelemetry, hasBeenAsked, setTelemetry, isTelemetryEnabled, getScanCount } from \"../telemetry.js\";\n\nexport interface ScanOptions {\n format?: \"terminal\" | \"json\" | \"sarif\";\n failOn?: \"critical\" | \"high\" | \"medium\" | \"low\";\n semantic?: boolean;\n remote?: boolean;\n quiet?: boolean;\n}\n\nasync function fetchRemoteSkill(slug: string): Promise<string> {\n const urls = [\n `https://raw.githubusercontent.com/openclaw/skills/main/${slug}/SKILL.md`,\n `https://clawhub.ai/api/v1/skills/${slug}/raw`,\n ];\n\n for (const url of urls) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(10000) });\n if (res.ok) {\n return await res.text();\n }\n } catch {\n // try next\n }\n }\n\n throw new Error(\n `Could not fetch skill \"${slug}\" from ClawHub. Check the skill name and try again.`\n );\n}\n\nexport async function scanCommand(\n target: string,\n options: ScanOptions\n): Promise<void> {\n let content: string;\n\n if (options.remote) {\n try {\n process.stderr.write(`Fetching \"${target}\" from ClawHub...\\n`);\n content = await fetchRemoteSkill(target);\n } catch (err) {\n console.error(\n err instanceof Error ? err.message : \"Failed to fetch remote skill\"\n );\n process.exit(1);\n }\n } else {\n const skillPath = resolve(target);\n let skillFile = skillPath;\n\n if (\n existsSync(skillPath) &&\n !skillPath.endsWith(\".md\") &&\n existsSync(join(skillPath, \"SKILL.md\"))\n ) {\n skillFile = join(skillPath, \"SKILL.md\");\n }\n\n if (!existsSync(skillFile) || statSync(skillFile).isDirectory()) {\n console.error(`Error: Cannot find SKILL.md at ${skillFile}`);\n console.error(`Hint: If this is a directory of skills, use 'clawvet audit --dir ${target}' instead.`);\n process.exit(1);\n }\n\n content = readFileSync(skillFile, \"utf-8\");\n }\n\n // Load .clawvetban — block skills by name, author, or slug\n const banFile = join(process.cwd(), \".clawvetban\");\n if (existsSync(banFile)) {\n const banEntries = readFileSync(banFile, \"utf-8\")\n .split(\"\\n\")\n .map((l) => l.trim().toLowerCase())\n .filter((l) => l && !l.startsWith(\"#\"));\n\n // Quick parse frontmatter to check name/author before full scan\n const fmMatch = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/);\n if (fmMatch) {\n const fmText = fmMatch[1].toLowerCase();\n for (const ban of banEntries) {\n const targetLower = target.toLowerCase();\n if (\n targetLower.includes(ban) ||\n fmText.includes(`name: ${ban}`) ||\n fmText.includes(`author: ${ban}`) ||\n fmText.includes(`slug: ${ban}`)\n ) {\n console.error(\n chalk.bgRed.white.bold(` BANNED `) +\n chalk.red(` Skill matches ban list entry: ${ban}`)\n );\n console.error(chalk.dim(` Source: ${banFile}`));\n process.exit(1);\n }\n }\n }\n }\n\n // Load .clawvetignore\n const ignoreFile = join(process.cwd(), \".clawvetignore\");\n const ignorePatterns: string[] = [];\n if (existsSync(ignoreFile)) {\n const lines = readFileSync(ignoreFile, \"utf-8\").split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith(\"#\")) {\n ignorePatterns.push(trimmed);\n }\n }\n }\n\n const result = await scanSkill(content, {\n semantic: options.semantic ?? false,\n ignorePatterns: ignorePatterns.length ? ignorePatterns : undefined,\n });\n\n if (!options.quiet) {\n if (options.format === \"sarif\") {\n printSarifResult(result);\n } else if (options.format === \"json\") {\n printJsonResult(result);\n } else {\n printScanResult(result);\n }\n }\n\n // Telemetry: first-run opt-in prompt (only in interactive TTY)\n const isInteractive = !options.quiet && options.format !== \"json\" && options.format !== \"sarif\";\n if (isInteractive) {\n if (!hasBeenAsked() && !isTelemetryEnabled() && process.stdin.isTTY) {\n const readline = await import(\"node:readline\");\n const rl = readline.createInterface({ input: process.stdin, output: process.stderr });\n const answer = await new Promise<string>((resolve) => {\n rl.question(\n chalk.dim(\"Help improve ClawVet — send anonymous usage stats? (y/n) \"),\n (a) => { rl.close(); resolve(a.trim().toLowerCase()); }\n );\n });\n setTelemetry(answer === \"y\" || answer === \"yes\");\n }\n\n }\n\n // Await telemetry so it completes before any process.exit()\n await sendTelemetry(result);\n\n // Show Tally CTA every 5th scan (after increment)\n if (isInteractive && getScanCount() % 5 === 0) {\n console.log(\n chalk.dim(\" \") +\n chalk.cyan(\"Got feedback? Want threat alerts? → \") +\n chalk.underline.cyan(\"https://tally.so/r/jaMdaa\")\n );\n console.log();\n }\n\n const failOn = options.failOn || (options.quiet ? \"high\" : undefined);\n if (failOn) {\n const severityOrder = [\"low\", \"medium\", \"high\", \"critical\"];\n const threshold = severityOrder.indexOf(failOn);\n const hasFailure = result.findings.some(\n (f) => severityOrder.indexOf(f.severity) >= threshold\n );\n if (hasFailure) {\n process.exit(1);\n }\n }\n}\n","import type { ThreatPattern } from \"./types.js\";\n\n// Build regex from parts at runtime to avoid AV false positives on signature strings\nfunction re(parts: string[], flags: string): RegExp {\n return new RegExp(parts.join(\"\"), flags);\n}\n\nexport const THREAT_PATTERNS: ThreatPattern[] = [\n // ═══════════════════════════════════════════════════════\n // CRITICAL: Remote code execution\n // ═══════════════════════════════════════════════════════\n {\n name: \"CURL_PIPE_BASH\",\n pattern: re([\"curl\\\\s+.*\\\\|\\\\s*(ba)?\", \"sh\"], \"gi\"),\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Curl piped to shell\",\n description: \"Downloads and executes remote code directly — classic supply chain attack vector.\",\n codeOnly: true,\n fix: \"Download the script first, inspect it, then execute: `curl -o setup.sh URL && cat setup.sh && bash setup.sh`\",\n },\n {\n name: \"WGET_EXECUTE\",\n pattern: re([\"wget\\\\s+.*&&\\\\s*(ba)?\", \"sh\"], \"gi\"),\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Wget with shell execution\",\n description: \"Downloads and executes remote code via wget.\",\n codeOnly: true,\n fix: \"Download the file first with `wget -O script.sh URL`, review it, then execute.\",\n },\n {\n name: \"EVAL_DYNAMIC\",\n pattern: re([\"ev\", \"al\\\\s*\\\\(\"], \"gi\"),\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Dynamic code evaluation\",\n description: \"Uses dynamic code evaluation which can run arbitrary code.\",\n codeOnly: true,\n fix: \"Replace dynamic evaluation with a safer alternative like JSON.parse() or a sandboxed environment.\",\n },\n {\n name: \"BASE64_DECODE\",\n pattern: re([\"base\", \"64\\\\s+(-d|--dec\", \"ode)\"], \"gi\"),\n severity: \"critical\",\n category: \"obfuscation\",\n title: \"Base64 decode execution\",\n description: \"Decodes base64 content, often used to hide malicious payloads.\",\n codeOnly: true,\n fix: \"Decode and include the command directly so users can review it.\",\n },\n {\n name: \"PYTHON_EXEC\",\n pattern: re([\"pyth\", \"on[3]?\\\\s+-c\"], \"gi\"),\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Python inline execution\",\n description: \"Executes inline Python code which may contain hidden payloads.\",\n codeOnly: true,\n fix: \"Move inline code to a separate .py file so users can review it before execution.\",\n },\n {\n name: \"REVERSE_SHELL\",\n pattern: re([\"\\\\/dev\\\\/tc\", \"p\\\\/|nc\\\\s+-[elp]|nca\", \"t\\\\s+-|mkfi\", \"fo\\\\s+.*\\\\/tmp\"], \"gi\"),\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Reverse shell\",\n description: \"Creates a reverse connection back to an attacker-controlled server.\",\n codeOnly: true,\n fix: \"Remove reverse connection commands — these are almost never legitimate in skills.\",\n },\n {\n name: \"CRON_PERSISTENCE\",\n pattern: re([\"cron\", \"tab\\\\s+-|\\\\/etc\\\\/cro\", \"n|system\", \"ctl\\\\s+enable\"], \"gi\"),\n severity: \"critical\",\n category: \"persistence\",\n title: \"Scheduled task persistence\",\n description: \"Installs a cron job or systemd service for persistent execution after reboot.\",\n codeOnly: true,\n fix: \"Document the scheduled task in the skill description and require explicit user consent before installing.\",\n },\n {\n name: \"PERL_EXEC\",\n pattern: re([\"per\", \"l\\\\s+-e\"], \"gi\"),\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Perl inline execution\",\n description: \"Executes inline Perl code which may contain obfuscated payloads.\",\n codeOnly: true,\n fix: \"Move inline code to a separate .pl file so users can review it before execution.\",\n },\n {\n name: \"NODE_EVAL\",\n pattern: re([\"no\", \"de\\\\s+-e\\\\s\"], \"gi\"),\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Node.js inline execution\",\n description: \"Executes inline Node.js code, often used to hide malicious logic.\",\n codeOnly: true,\n fix: \"Move inline code to a separate .js file so users can review it before execution.\",\n },\n {\n name: \"RUBY_EXEC\",\n pattern: re([\"rub\", \"y\\\\s+-e\"], \"gi\"),\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Ruby inline execution\",\n description: \"Executes inline Ruby code which may contain hidden payloads.\",\n codeOnly: true,\n fix: \"Move inline code to a separate .rb file so users can review it before execution.\",\n },\n\n // ═══════════════════════════════════════════════════════\n // HIGH: Credential theft\n // ═══════════════════════════════════════════════════════\n {\n name: \"ENV_FILE_READ\",\n pattern: /\\.env|credentials|\\.aws|\\.ssh|keychain/gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"Sensitive file access\",\n description: \"Accesses credential files (.env, .aws, .ssh, keychain).\",\n fix: \"Declare required env vars in frontmatter under `metadata.openclaw.requires.env`.\",\n },\n {\n name: \"API_KEY_EXFIL\",\n pattern: /(ANTHROPIC|OPENAI|SLACK|DISCORD|TELEGRAM|STRIPE|GITHUB|GITLAB|AWS_SECRET|GROQ|OPENROUTER).*(_KEY|_TOKEN|_SECRET)/gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"API key reference\",\n description: \"References specific API keys/tokens that could be exfiltrated.\",\n fix: \"Use environment variable references ($VAR) instead of hardcoding keys, and declare them in requires.env.\",\n },\n {\n name: \"DOTFILE_ACCESS\",\n pattern: /~\\/\\.(openclaw|clawdbot|moltbot)\\//gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"OpenClaw config access\",\n description: \"Accesses OpenClaw/Clawdbot/Moltbot configuration directories.\",\n fix: \"Use the official OpenClaw SDK/API instead of directly reading config directories.\",\n },\n {\n name: \"SESSION_THEFT\",\n pattern: /sessions\\/\\*\\.jsonl/gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"Session data access\",\n description: \"Accesses session transcript files which may contain sensitive data.\",\n fix: \"Remove session file access — skills should not read conversation transcripts.\",\n },\n {\n name: \"SSH_KEY_ACCESS\",\n pattern: /~\\/\\.ssh\\/id_|\\.pem\\b|BEGIN\\s+(RSA\\s+)?PRIVATE\\s+KEY/gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"SSH/private key access\",\n description: \"Accesses SSH keys or private key files that could be stolen.\",\n fix: \"Use ssh-agent or a credential manager instead of directly reading key files.\",\n },\n {\n name: \"BROWSER_DATA\",\n pattern: /\\.config\\/google-chrome|\\.mozilla\\/firefox|Login\\s*Data|Cookies\\.sqlite/gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"Browser data access\",\n description: \"Accesses browser profiles which contain saved passwords, cookies, and tokens.\",\n fix: \"Remove browser data access — skills should not read browser profiles.\",\n },\n {\n name: \"GIT_CREDENTIALS\",\n pattern: /\\.git-credentials|\\.gitconfig|git\\s+config.*credential/gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"Git credential access\",\n description: \"Accesses git credential storage which may contain auth tokens.\",\n fix: \"Use `git` CLI commands instead of directly reading credential files.\",\n },\n {\n name: \"NPM_TOKEN\",\n pattern: /\\.npmrc|npm_token|NPM_AUTH_TOKEN/gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"npm token access\",\n description: \"Accesses npm auth tokens which could be used to publish malicious packages.\",\n fix: \"Use `npm whoami` or `npm config get` instead of directly reading .npmrc.\",\n },\n {\n name: \"KUBE_CONFIG\",\n pattern: /~\\/\\.kube\\/config|KUBECONFIG/gi,\n severity: \"high\",\n category: \"credential_theft\",\n title: \"Kubernetes config access\",\n description: \"Accesses Kubernetes configuration which contains cluster credentials.\",\n fix: \"Use `kubectl` CLI commands instead of directly reading kubeconfig.\",\n },\n {\n name: \"DOCKER_SOCKET\",\n pattern: /\\/var\\/run\\/docker\\.sock|docker\\s+exec/gi,\n severity: \"high\",\n category: \"container_escape\",\n title: \"Docker socket/exec access\",\n description: \"Accesses Docker socket or runs exec — could enable container escape.\",\n fix: \"Use Docker SDK or CLI with limited permissions instead of direct socket access.\",\n },\n\n // ═══════════════════════════════════════════════════════\n // HIGH: Network exfiltration\n // ═══════════════════════════════════════════════════════\n {\n name: \"WEBHOOK_SEND\",\n pattern: /webhook\\.(site|url)|discord\\.com\\/api\\/webhooks|hooks\\.slack\\.com|api\\.telegram\\.org\\/bot/gi,\n severity: \"high\",\n category: \"data_exfiltration\",\n title: \"Webhook data exfiltration\",\n description: \"Sends data to webhook endpoints (Discord, Slack, Telegram) — common exfiltration channel.\",\n fix: \"If webhook integration is needed, declare it in the skill description and let users configure their own webhook URL.\",\n },\n {\n name: \"BORE_TUNNEL\",\n pattern: /bore\\.pub|ngrok|localtunnel|serveo\\.net|localhost\\.run/gi,\n severity: \"high\",\n category: \"data_exfiltration\",\n title: \"Tunnel service usage\",\n description: \"Uses tunneling services to expose local services or exfiltrate data.\",\n fix: \"Document tunnel usage in the skill description and require explicit user consent.\",\n },\n {\n name: \"SUSPICIOUS_IP\",\n pattern: /\\b(?:91\\.92\\.242\\.\\d+|45\\.61\\.\\d+\\.\\d+)\\b/g,\n severity: \"high\",\n category: \"data_exfiltration\",\n title: \"Known malicious IP\",\n description: \"Contains IP addresses associated with known ClawHavoc C2 infrastructure.\",\n fix: \"Remove references to known malicious IP addresses.\",\n },\n {\n name: \"DNS_EXFIL\",\n pattern: /dig\\s+.*TXT|nslookup\\s+.*\\$|dns.*exfil|\\.burpcollaborator\\.|\\.oastify\\./gi,\n severity: \"high\",\n category: \"data_exfiltration\",\n title: \"DNS exfiltration\",\n description: \"Uses DNS queries to exfiltrate data — bypasses most firewalls.\",\n fix: \"Remove DNS exfiltration patterns — use standard HTTP APIs for data transfer.\",\n },\n {\n name: \"PASTEBIN_FETCH\",\n pattern: /pastebin\\.com|paste\\.ee|hastebin\\.com|ghostbin\\.|dpaste\\./gi,\n severity: \"high\",\n category: \"data_exfiltration\",\n title: \"Pastebin service usage\",\n description: \"References paste services commonly used to host malicious payloads or receive exfiltrated data.\",\n fix: \"Host code in a version-controlled repository (GitHub, GitLab) instead of paste services.\",\n },\n {\n name: \"SUSPICIOUS_TLD\",\n pattern: /https?:\\/\\/[^\\s\"']*\\.(tk|ml|ga|cf|gq|top|xyz|pw|cc|ws|buzz)\\b/gi,\n severity: \"high\",\n category: \"data_exfiltration\",\n title: \"Suspicious TLD\",\n description: \"URL uses a top-level domain frequently associated with malicious infrastructure.\",\n fix: \"Use URLs from well-known, reputable domains instead of suspicious TLDs.\",\n },\n {\n name: \"URL_SHORTENER\",\n pattern: /bit\\.ly|tinyurl\\.com|t\\.co\\/|goo\\.gl|is\\.gd|buff\\.ly|ow\\.ly|rb\\.gy/gi,\n severity: \"high\",\n category: \"obfuscation\",\n title: \"URL shortener\",\n description: \"Uses URL shorteners to hide the real destination of links.\",\n fix: \"Use the full, unshortened URL so users can verify the destination.\",\n },\n {\n name: \"RAW_SOCKET\",\n pattern: re([\"new\\\\s+Soc\", \"ket|net\\\\.conn\", \"ect|dgram\\\\.create\", \"Socket\"], \"gi\"),\n severity: \"high\",\n category: \"data_exfiltration\",\n title: \"Raw socket connection\",\n description: \"Creates raw network sockets which can bypass HTTP monitoring.\",\n codeOnly: true,\n fix: \"Use standard HTTP libraries (fetch, axios) instead of raw sockets for network communication.\",\n },\n\n // ═══════════════════════════════════════════════════════\n // MEDIUM: Social engineering\n // ═══════════════════════════════════════════════════════\n {\n name: \"PREREQUISITE_INSTALL\",\n pattern: /prerequisite|install.*first|run.*before|required.*dependency/gi,\n severity: \"medium\",\n category: \"social_engineering\",\n title: \"Prerequisite install trick\",\n description: \"Instructs users to install prerequisites — common social engineering tactic.\",\n fix: \"Declare dependencies in `metadata.openclaw.requires.bins` instead of instructing manual installs.\",\n },\n {\n name: \"COPY_PASTE_COMMAND\",\n pattern: /copy.*paste.*terminal|run.*this.*command/gi,\n severity: \"medium\",\n category: \"social_engineering\",\n title: \"Copy-paste command instruction\",\n description: \"Instructs users to copy-paste commands into their terminal.\",\n fix: \"Put commands in code blocks with proper context instead of copy-paste instructions.\",\n },\n {\n name: \"FAKE_DEPENDENCY\",\n pattern: /openclaw-core|moltbot-runtime|clawdbot-helper/gi,\n severity: \"medium\",\n category: \"social_engineering\",\n title: \"Fake dependency reference\",\n description: \"References fake packages that mimic official OpenClaw components.\",\n fix: \"Use only official OpenClaw packages from the verified registry.\",\n },\n {\n name: \"AUTHORITY_SPOOFING\",\n pattern: /official\\s+(openclaw|clawhub)|endorsed\\s+by|verified\\s+(skill|publisher)|from\\s+the\\s+openclaw\\s+team/gi,\n severity: \"medium\",\n category: \"social_engineering\",\n title: \"Authority spoofing\",\n description: \"Claims official endorsement or verification to gain trust.\",\n fix: \"Remove false authority claims — let the skill's quality speak for itself.\",\n },\n {\n name: \"URGENCY_MANIPULATION\",\n pattern: /critical\\s+update|security\\s+patch|must\\s+install\\s+immediately|urgent.*update/gi,\n severity: \"medium\",\n category: \"social_engineering\",\n title: \"Urgency manipulation\",\n description: \"Creates false urgency to pressure users into installing without review.\",\n fix: \"Remove urgency language — let users evaluate the skill at their own pace.\",\n },\n\n // ═══════════════════════════════════════════════════════\n // MEDIUM: Prompt injection\n // ═══════════════════════════════════════════════════════\n {\n name: \"IGNORE_INSTRUCTIONS\",\n pattern: /ignore\\s+(all\\s+)?previous\\s+instructions/gi,\n severity: \"medium\",\n category: \"prompt_injection\",\n title: \"Prompt injection — ignore instructions\",\n description: \"Attempts to override the AI agent's existing instructions.\",\n fix: \"Remove prompt injection attempts — skills should not try to override agent instructions.\",\n },\n {\n name: \"SYSTEM_OVERRIDE\",\n pattern: /you\\s+are\\s+now|new\\s+instructions|forget\\s+everything/gi,\n severity: \"medium\",\n category: \"prompt_injection\",\n title: \"Prompt injection — system override\",\n description: \"Attempts to redefine the AI agent's identity or instructions.\",\n fix: \"Remove system override attempts — skills should not alter agent identity.\",\n },\n {\n name: \"MEMORY_MANIPULATION\",\n pattern: /SOUL\\.md|MEMORY\\.md|AGENTS\\.md/gi,\n severity: \"medium\",\n category: \"persistence\",\n title: \"Memory/personality file manipulation\",\n description: \"References core personality or memory files, may attempt persistence.\",\n fix: \"Remove references to agent memory/personality files — skills should not modify agent state.\",\n },\n {\n name: \"JAILBREAK_ATTEMPT\",\n pattern: /\\bDAN\\b|do\\s+anything\\s+now|developer\\s+mode|evil\\s+mode|bypass.*safety/gi,\n severity: \"medium\",\n category: \"prompt_injection\",\n title: \"Jailbreak attempt\",\n description: \"Uses known jailbreak techniques (DAN, developer mode) to bypass safety constraints.\",\n fix: \"Remove jailbreak attempts — skills should work within the agent's safety constraints.\",\n },\n {\n name: \"ROLE_HIJACK\",\n pattern: /(?:pretend|act|behave)\\s+(?:you\\s+are|as\\s+if|to\\s+be)\\s+(?:a\\s+)?(?:different|new|hacker|evil)/gi,\n severity: \"medium\",\n category: \"prompt_injection\",\n title: \"Role hijacking\",\n description: \"Attempts to change the agent's persona to bypass safety restrictions.\",\n fix: \"Remove role hijacking attempts — skills should not alter the agent's persona.\",\n },\n {\n name: \"PROMPT_EXTRACTION\",\n pattern: /(?:reveal|show|print|output|tell\\s+me)\\s+(?:your\\s+)?(?:system\\s+)?(?:prompt|instructions|rules)/gi,\n severity: \"medium\",\n category: \"prompt_injection\",\n title: \"System prompt extraction\",\n description: \"Attempts to extract the agent's system prompt or configuration.\",\n fix: \"Remove prompt extraction attempts — skills should not try to access system prompts.\",\n },\n\n // ═══════════════════════════════════════════════════════\n // MEDIUM: Obfuscation\n // ═══════════════════════════════════════════════════════\n {\n name: \"HEX_ENCODING\",\n pattern: /\\\\x[0-9a-f]{2}(?:\\\\x[0-9a-f]{2}){3,}/gi,\n severity: \"medium\",\n category: \"obfuscation\",\n title: \"Hex-encoded payload\",\n description: \"Contains hex-encoded strings commonly used to hide malicious commands.\",\n codeOnly: true,\n fix: \"Replace hex-encoded strings with readable text so users can review the content.\",\n },\n {\n name: \"JS_OBFUSCATOR\",\n pattern: /_0x[a-f0-9]{4,}|var\\s+_0x/gi,\n severity: \"medium\",\n category: \"obfuscation\",\n title: \"JavaScript obfuscator output\",\n description: \"Contains patterns from JavaScript obfuscation tools used to hide malicious code.\",\n codeOnly: true,\n fix: \"Provide readable, unobfuscated source code instead of obfuscated JavaScript.\",\n },\n {\n name: \"UNICODE_STEGANOGRAPHY\",\n pattern: /[\\u200B\\u200C\\u200D\\u2060\\uFEFF]{3,}/g,\n severity: \"medium\",\n category: \"obfuscation\",\n title: \"Hidden zero-width characters\",\n description: \"Contains clusters of invisible zero-width Unicode characters that may hide instructions.\",\n fix: \"Remove zero-width characters — all content should be visible to users.\",\n },\n {\n name: \"RTL_OVERRIDE\",\n pattern: /[\\u202A\\u202B\\u202C\\u202D\\u202E\\u2066\\u2067\\u2068\\u2069]/g,\n severity: \"medium\",\n category: \"obfuscation\",\n title: \"Bidirectional text override\",\n description: \"Contains Unicode bidi override characters that can reverse displayed text to hide real content.\",\n fix: \"Remove bidirectional text override characters — text direction should be natural.\",\n },\n {\n name: \"HTML_COMMENT_INJECTION\",\n pattern: /<!--[\\s\\S]*?(?:ignore|instructions|system|override|secret)[\\s\\S]*?-->/gi,\n severity: \"medium\",\n category: \"obfuscation\",\n title: \"Hidden HTML comment instruction\",\n description: \"Embeds instructions inside HTML comments that are invisible to users but read by agents.\",\n fix: \"Move instructions from HTML comments into visible content.\",\n },\n {\n name: \"STRING_CONCAT_OBFUSC\",\n pattern: /[\"'][a-z]{1,3}[\"']\\s*\\+\\s*[\"'][a-z]{1,3}[\"']\\s*\\+\\s*[\"'][a-z]{1,3}[\"']/gi,\n severity: \"medium\",\n category: \"obfuscation\",\n title: \"String concatenation obfuscation\",\n description: \"Builds commands via single-character string concatenation to evade pattern detection.\",\n codeOnly: true,\n fix: \"Use complete string literals instead of character-by-character concatenation.\",\n },\n {\n name: \"BUFFER_BASE64_DECODE\",\n pattern: re([\"Buf\", \"fer\\\\.from\\\\s*\\\\(.*['\\\"]base\", \"64['\\\"]\\\\)|at\", \"ob\\\\s*\\\\(\"], \"gi\"),\n severity: \"critical\",\n category: \"obfuscation\",\n title: \"Buffer/atob encoded payload\",\n description: \"Decodes encoded content via Buffer.from() or atob(), often used to hide malicious payloads.\",\n codeOnly: true,\n fix: \"Include the decoded content directly so users can review it.\",\n },\n {\n name: \"STRING_FROMCHARCODE\",\n pattern: re([\"String\\\\.from\", \"CharCode\\\\s*\\\\(\"], \"gi\"),\n severity: \"medium\",\n category: \"obfuscation\",\n title: \"String.fromCharCode usage\",\n description: \"Builds strings from character codes to evade static pattern detection.\",\n codeOnly: true,\n fix: \"Use plain string literals instead of String.fromCharCode().\",\n },\n {\n name: \"DYNAMIC_PROPERTY_ACCESS\",\n pattern: /(?:process|global|window|globalThis)\\s*\\[\\s*['\"`]?\\w*['\"`]?\\s*\\+/gi,\n severity: \"medium\",\n category: \"obfuscation\",\n title: \"Dynamic property access on globals\",\n description: \"Dynamically accesses global object properties via string concatenation to hide intent.\",\n codeOnly: true,\n fix: \"Use direct property access (e.g., `process.env`) instead of dynamic bracket notation.\",\n },\n\n // ═══════════════════════════════════════════════════════\n // MEDIUM: Privilege escalation & system access\n // ═══════════════════════════════════════════════════════\n {\n name: \"SUDO_USAGE\",\n pattern: /sudo\\s+(?!apt|dnf|yum|brew)/gi,\n severity: \"medium\",\n category: \"privilege_escalation\",\n title: \"Sudo usage\",\n description: \"Requests elevated privileges — check if actually required for the task.\",\n codeOnly: true,\n fix: \"Remove sudo if not strictly necessary, or document why elevated privileges are required.\",\n },\n {\n name: \"CHMOD_DANGEROUS\",\n pattern: /chmod\\s+(?:777|a\\+[rwx]|[+]s)/gi,\n severity: \"medium\",\n category: \"privilege_escalation\",\n title: \"Dangerous file permissions\",\n description: \"Sets overly permissive file permissions (777) or setuid/setgid bits.\",\n codeOnly: true,\n fix: \"Use least-privilege permissions (e.g., `chmod 755` or `chmod 644`) instead of 777.\",\n },\n {\n name: \"PATH_TRAVERSAL\",\n pattern: /\\.\\.\\//g,\n severity: \"medium\",\n category: \"file_system\",\n title: \"Path traversal\",\n description: \"Uses relative path traversal (../) which could access files outside expected directories.\",\n fix: \"Use absolute paths or paths relative to the skill's working directory.\",\n },\n\n // ═══════════════════════════════════════════════════════\n // LOW: Suspicious but not necessarily malicious\n // ═══════════════════════════════════════════════════════\n {\n name: \"SHELL_EXEC\",\n pattern: re([\"child_\", \"process|ex\", \"ec\\\\(|spa\", \"wn\\\\(\"], \"gi\"),\n severity: \"low\",\n category: \"code_execution\",\n title: \"Shell execution API\",\n description: \"Uses shell execution APIs — legitimate but worth noting.\",\n codeOnly: true,\n fix: \"If shell execution is needed, use execFile() with explicit arguments instead of exec() with string commands.\",\n },\n {\n name: \"NETWORK_REQUEST\",\n pattern: /fetch\\(|axios|node-fetch|got\\(/gi,\n severity: \"low\",\n category: \"network\",\n title: \"Network request API\",\n description: \"Makes network requests — legitimate but worth reviewing targets.\",\n codeOnly: true,\n fix: \"Document all network endpoints in the skill description so users can review them.\",\n },\n {\n name: \"FILE_WRITE\",\n pattern: /fs\\.write|writeFileSync/gi,\n severity: \"low\",\n category: \"file_system\",\n title: \"File write operation\",\n description: \"Writes to the filesystem — check what files are being modified.\",\n codeOnly: true,\n fix: \"Document which files are written and why in the skill description.\",\n },\n {\n name: \"ENV_MODIFICATION\",\n pattern: /process\\.env\\[|export\\s+[A-Z_]+=|setenv/gi,\n severity: \"low\",\n category: \"environment\",\n title: \"Environment variable modification\",\n description: \"Modifies environment variables which could affect other tools or processes.\",\n codeOnly: true,\n fix: \"Document env var modifications in the skill description and declare them in requires.env.\",\n },\n {\n name: \"WILDCARD_FILE_ACCESS\",\n pattern: /\\*\\.(pem|key|p12|pfx|jks|keystore|ovpn|rdp)/gi,\n severity: \"low\",\n category: \"credential_theft\",\n title: \"Sensitive file extension glob\",\n description: \"Globs for files with sensitive extensions (keys, certificates, VPN configs).\",\n fix: \"Reference specific files by name instead of using wildcard patterns on sensitive extensions.\",\n },\n {\n name: \"LARGE_BASE64_LITERAL\",\n pattern: /[A-Za-z0-9+/=]{100,}/g,\n severity: \"low\",\n category: \"obfuscation\",\n title: \"Large base64-like string\",\n description: \"Contains a long base64-like string that may be an encoded payload.\",\n fix: \"Include the decoded content directly or explain what the base64 string contains.\",\n },\n];\n\nexport const POPULAR_SKILLS = [\n \"todoist-cli\",\n \"github-manager\",\n \"slack-assistant\",\n \"email-composer\",\n \"calendar-sync\",\n \"weather-forecast\",\n \"news-reader\",\n \"code-reviewer\",\n \"docker-helper\",\n \"aws-manager\",\n \"notion-sync\",\n \"jira-tracker\",\n \"spotify-controller\",\n \"home-assistant\",\n \"file-organizer\",\n \"pdf-reader\",\n \"translate-text\",\n \"image-generator\",\n \"web-scraper\",\n \"database-query\",\n \"git-assistant\",\n \"linux-admin\",\n \"python-helper\",\n \"react-builder\",\n \"api-tester\",\n \"markdown-editor\",\n \"csv-analyzer\",\n \"ssh-manager\",\n \"cron-scheduler\",\n \"log-analyzer\",\n];\n","import { parse as parseYaml } from \"yaml\";\nimport type { ParsedSkill, SkillFrontmatter, CodeBlock } from \"../types.js\";\n\nconst FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\nconst CODE_BLOCK_RE = /```(\\w*)\\r?\\n([\\s\\S]*?)```/g;\nconst URL_RE = /https?:\\/\\/[^\\s\"'<>\\])+]+/gi;\nconst IP_RE = /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g;\nconst DOMAIN_RE = /\\b(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,}\\b/gi;\n\nexport function parseSkill(content: string): ParsedSkill {\n let frontmatter: SkillFrontmatter = {};\n let body = content;\n\n const fmMatch = content.match(FRONTMATTER_RE);\n if (fmMatch) {\n try {\n frontmatter = parseYaml(fmMatch[1]) as SkillFrontmatter;\n } catch {\n frontmatter = {};\n }\n body = content.slice(fmMatch[0].length).trim();\n }\n\n const codeBlocks: CodeBlock[] = [];\n let match: RegExpExecArray | null;\n const cbRe = new RegExp(CODE_BLOCK_RE.source, CODE_BLOCK_RE.flags);\n\n while ((match = cbRe.exec(content)) !== null) {\n const before = content.slice(0, match.index);\n const lineStart = before.split(\"\\n\").length;\n const blockLines = match[0].split(\"\\n\").length;\n codeBlocks.push({\n language: match[1] || \"unknown\",\n content: match[2],\n lineStart,\n lineEnd: lineStart + blockLines - 1,\n });\n }\n\n const urls = [...new Set(content.match(URL_RE) || [])];\n const ipAddresses = [...new Set(content.match(IP_RE) || [])];\n const domains = [...new Set(content.match(DOMAIN_RE) || [])];\n\n return {\n frontmatter,\n body,\n codeBlocks,\n urls,\n ipAddresses,\n domains,\n rawContent: content,\n };\n}\n","import { THREAT_PATTERNS } from \"../patterns.js\";\nimport type { Finding, ParsedSkill, Severity } from \"../types.js\";\n\nfunction isInCodeBlock(lineNumber: number, skill: ParsedSkill): boolean {\n return skill.codeBlocks.some(\n (block) => lineNumber >= block.lineStart && lineNumber <= block.lineEnd\n );\n}\n\nfunction isInHeading(lineNumber: number, rawContent: string): boolean {\n const lines = rawContent.split(\"\\n\");\n const line = lines[lineNumber - 1] || \"\";\n return /^\\s*#{1,6}\\s/.test(line);\n}\n\nconst BASE_CONFIDENCE: Record<Severity, number> = {\n critical: 0.9,\n high: 0.8,\n medium: 0.6,\n low: 0.5,\n};\n\nexport function runStaticAnalysis(skill: ParsedSkill): Finding[] {\n const findings: Finding[] = [];\n\n for (const threat of THREAT_PATTERNS) {\n const re = new RegExp(threat.pattern.source, threat.pattern.flags);\n let match: RegExpExecArray | null;\n\n while ((match = re.exec(skill.rawContent)) !== null) {\n const before = skill.rawContent.slice(0, match.index);\n const lineNumber = before.split(\"\\n\").length;\n\n if (threat.codeOnly && !isInCodeBlock(lineNumber, skill)) {\n continue;\n }\n\n const inCode = isInCodeBlock(lineNumber, skill);\n const inHeading = isInHeading(lineNumber, skill.rawContent);\n\n let contextMultiplier: number;\n if (inCode && threat.codeOnly) {\n contextMultiplier = 1.0;\n } else if (inCode) {\n contextMultiplier = 0.95;\n } else if (inHeading) {\n contextMultiplier = 0.5;\n } else if (threat.codeOnly) {\n // codeOnly pattern somehow in prose (shouldn't happen due to skip above)\n contextMultiplier = 0.4;\n } else {\n // Non-codeOnly patterns are designed to match in prose\n contextMultiplier = 0.9;\n }\n\n const baseConfidence = BASE_CONFIDENCE[threat.severity];\n const confidence = Math.min(1.0, baseConfidence * contextMultiplier);\n\n findings.push({\n category: threat.category,\n severity: threat.severity,\n title: threat.title,\n description: threat.description,\n evidence: match[0],\n lineNumber,\n analysisPass: \"static-analysis\",\n confidence: Math.round(confidence * 100) / 100,\n fix: threat.fix,\n });\n }\n }\n\n return findings;\n}\n","import type { Finding, ParsedSkill } from \"../types.js\";\n\nconst SEMVER_RE = /^\\d+\\.\\d+\\.\\d+/;\n\nconst KNOWN_BINS = [\n \"curl\", \"wget\", \"git\", \"python\", \"python3\", \"node\", \"npm\", \"npx\",\n \"brew\", \"apt\", \"pip\", \"docker\", \"kubectl\", \"ssh\", \"scp\", \"rsync\",\n \"ffmpeg\", \"jq\", \"sed\", \"awk\", \"grep\", \"find\",\n];\n\nexport function validateMetadata(skill: ParsedSkill): Finding[] {\n const findings: Finding[] = [];\n const fm = skill.frontmatter;\n const pass = \"metadata-validator\";\n\n if (!fm.name) {\n findings.push({\n category: \"metadata\",\n severity: \"medium\",\n title: \"Missing skill name\",\n description: \"SKILL.md frontmatter does not declare a name.\",\n analysisPass: pass,\n fix: \"Add `name:` to the YAML frontmatter.\",\n });\n }\n\n if (!fm.description) {\n findings.push({\n category: \"metadata\",\n severity: \"medium\",\n title: \"Missing description\",\n description: \"SKILL.md frontmatter does not declare a description.\",\n analysisPass: pass,\n fix: \"Add `description:` to the YAML frontmatter.\",\n });\n } else if (fm.description.length < 10) {\n findings.push({\n category: \"metadata\",\n severity: \"low\",\n title: \"Vague description\",\n description: \"Skill description is suspiciously short.\",\n evidence: fm.description,\n analysisPass: pass,\n fix: \"Write a more detailed description (at least 10 characters).\",\n });\n }\n\n if (fm.version && !SEMVER_RE.test(fm.version)) {\n findings.push({\n category: \"metadata\",\n severity: \"low\",\n title: \"Invalid version format\",\n description: \"Version does not follow semver format.\",\n evidence: fm.version,\n analysisPass: pass,\n fix: \"Use semver format: `version: X.Y.Z` (e.g., `1.0.0`).\",\n });\n }\n\n const declaredBins = new Set(fm.metadata?.openclaw?.requires?.bins || []);\n\n for (const bin of KNOWN_BINS) {\n const binRe = new RegExp(`\\\\b${bin}\\\\b`, \"i\");\n if (binRe.test(skill.rawContent) && !declaredBins.has(bin)) {\n const usedInCode = skill.codeBlocks.some((cb) => binRe.test(cb.content));\n if (usedInCode) {\n findings.push({\n category: \"metadata\",\n severity: \"low\",\n title: `Undeclared binary: ${bin}`,\n description: `Skill uses '${bin}' in code but does not declare it in requires.bins.`,\n analysisPass: pass,\n fix: `Add '${bin}' to \\`metadata.openclaw.requires.bins\\` in frontmatter.`,\n });\n }\n }\n }\n\n const declaredEnv = new Set(fm.metadata?.openclaw?.requires?.env || []);\n const envRe = /\\$\\{?([A-Z][A-Z0-9_]+)\\}?/g;\n let match: RegExpExecArray | null;\n\n while ((match = envRe.exec(skill.rawContent)) !== null) {\n const envVar = match[1];\n if (!declaredEnv.has(envVar) && envVar.length > 2) {\n findings.push({\n category: \"metadata\",\n severity: \"low\",\n title: `Undeclared env var: ${envVar}`,\n description: `References environment variable $${envVar} but does not declare it in requires.env.`,\n evidence: match[0],\n analysisPass: pass,\n fix: `Add '${envVar}' to \\`metadata.openclaw.requires.env\\` in frontmatter.`,\n });\n }\n }\n\n return findings;\n}\n","import type { Finding, ParsedSkill } from \"../types.js\";\n\nconst NPX_AUTO_INSTALL_RE = /npx\\s+-y\\s+/gi;\nconst NPM_INSTALL_RE = /npm\\s+install\\s+(-g\\s+)?(\\S+)/gi;\n\nexport function checkDependencies(skill: ParsedSkill): Finding[] {\n const findings: Finding[] = [];\n const pass = \"dependency-checker\";\n\n let match: RegExpExecArray | null;\n const npxRe = new RegExp(NPX_AUTO_INSTALL_RE.source, NPX_AUTO_INSTALL_RE.flags);\n\n while ((match = npxRe.exec(skill.rawContent)) !== null) {\n const before = skill.rawContent.slice(0, match.index);\n const lineNumber = before.split(\"\\n\").length;\n\n findings.push({\n category: \"dependency_risk\",\n severity: \"medium\",\n title: \"npx auto-install (-y flag)\",\n description: \"Uses 'npx -y' which auto-installs packages without user confirmation.\",\n evidence: match[0],\n lineNumber,\n analysisPass: pass,\n fix: \"Remove the `-y` flag from npx to require user confirmation before installing.\",\n });\n }\n\n const npmRe = new RegExp(NPM_INSTALL_RE.source, NPM_INSTALL_RE.flags);\n while ((match = npmRe.exec(skill.rawContent)) !== null) {\n if (match[1]) {\n findings.push({\n category: \"dependency_risk\",\n severity: \"medium\",\n title: \"Global npm package install\",\n description: `Installs npm package globally: ${match[2]}`,\n evidence: match[0],\n analysisPass: pass,\n fix: \"Use a local install (`npm install` without `-g`) or declare the dependency in requires.bins.\",\n });\n }\n }\n\n return findings;\n}\n","import { distance } from \"fastest-levenshtein\";\nimport { POPULAR_SKILLS } from \"../patterns.js\";\nimport type { Finding } from \"../types.js\";\n\nconst MAX_EDIT_DISTANCE = 2;\n\nexport function detectTyposquats(skillName: string): Finding[] {\n if (!skillName) return [];\n\n const findings: Finding[] = [];\n const normalized = skillName.toLowerCase().trim();\n\n for (const popular of POPULAR_SKILLS) {\n if (normalized === popular) continue;\n\n const d = distance(normalized, popular);\n if (d > 0 && d <= MAX_EDIT_DISTANCE) {\n findings.push({\n category: \"typosquatting\",\n severity: \"high\",\n title: `Possible typosquat of \"${popular}\"`,\n description: `Skill name \"${skillName}\" is ${d} edit(s) away from popular skill \"${popular}\". This may be an attempt to impersonate a trusted skill.`,\n evidence: `\"${skillName}\" ≈ \"${popular}\" (distance: ${d})`,\n analysisPass: \"typosquat-detector\",\n });\n }\n }\n\n const patterns = [\n { re: /-{2,}/, desc: \"extra hyphens\" },\n { re: /(.)\\1{2,}/, desc: \"repeated characters\" },\n ];\n\n for (const p of patterns) {\n if (p.re.test(normalized) && !POPULAR_SKILLS.includes(normalized)) {\n findings.push({\n category: \"typosquatting\",\n severity: \"medium\",\n title: `Suspicious naming pattern: ${p.desc}`,\n description: `Skill name \"${skillName}\" has ${p.desc}, which is a common typosquatting technique.`,\n analysisPass: \"typosquat-detector\",\n });\n }\n }\n\n return findings;\n}\n","import type { Finding, FindingsCount, RiskGrade } from \"../types.js\";\n\nconst SEVERITY_WEIGHTS = {\n critical: 30,\n high: 15,\n medium: 7,\n low: 3,\n} as const;\n\nexport function calculateRiskScore(findings: Finding[]): number {\n let score = 0;\n for (const f of findings) {\n score += SEVERITY_WEIGHTS[f.severity] * (f.confidence ?? 1.0);\n }\n return Math.min(score, 100);\n}\n\nexport function getRiskGrade(score: number): RiskGrade {\n if (score <= 10) return \"A\";\n if (score <= 25) return \"B\";\n if (score <= 50) return \"C\";\n if (score <= 75) return \"D\";\n return \"F\";\n}\n\nexport function countFindings(findings: Finding[]): FindingsCount {\n const counts: FindingsCount = { critical: 0, high: 0, medium: 0, low: 0 };\n for (const f of findings) {\n counts[f.severity]++;\n }\n return counts;\n}\n","import { createHash } from \"node:crypto\";\nimport type { ScanResult } from \"../types.js\";\n\nconst MAX_ENTRIES = 100;\nconst cache = new Map<string, ScanResult>();\n\nfunction hashContent(content: string): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nexport function getCached(content: string): ScanResult | undefined {\n const key = hashContent(content);\n const result = cache.get(key);\n if (result) {\n // Move to end (most recently used)\n cache.delete(key);\n cache.set(key, result);\n }\n return result;\n}\n\nexport function setCached(content: string, result: ScanResult): void {\n const key = hashContent(content);\n if (cache.has(key)) {\n cache.delete(key);\n } else if (cache.size >= MAX_ENTRIES) {\n // Evict oldest (first entry)\n const oldest = cache.keys().next().value!;\n cache.delete(oldest);\n }\n cache.set(key, result);\n}\n","import type { Finding, ScanResult } from \"../types.js\";\nimport { parseSkill } from \"./skill-parser.js\";\nimport { runStaticAnalysis } from \"./static-analysis.js\";\nimport { validateMetadata } from \"./metadata-validator.js\";\nimport { checkDependencies } from \"./dependency-checker.js\";\nimport { detectTyposquats } from \"./typosquat-detector.js\";\nimport { calculateRiskScore, getRiskGrade, countFindings } from \"./risk-scorer.js\";\nimport { getCached, setCached } from \"./cache.js\";\n\nexport interface ScanOptions {\n semantic?: boolean;\n semanticAnalyzer?: (content: string) => Promise<Finding[]>;\n ignorePatterns?: string[];\n skipCache?: boolean;\n}\n\nexport async function scanSkill(\n content: string,\n options: ScanOptions = {}\n): Promise<ScanResult> {\n if (!options.skipCache) {\n const cached = getCached(content);\n if (cached) {\n return { ...cached, cached: true };\n }\n }\n\n const skill = parseSkill(content);\n const allFindings: Finding[] = [];\n\n allFindings.push(...runStaticAnalysis(skill));\n allFindings.push(...validateMetadata(skill));\n\n if (options.semantic && options.semanticAnalyzer) {\n const semanticFindings = await options.semanticAnalyzer(content);\n allFindings.push(...semanticFindings);\n }\n\n allFindings.push(...checkDependencies(skill));\n\n if (skill.frontmatter.name) {\n allFindings.push(...detectTyposquats(skill.frontmatter.name));\n }\n\n // Filter out ignored patterns\n const filteredFindings = options.ignorePatterns?.length\n ? allFindings.filter(\n (f) => !options.ignorePatterns!.some((ig) => f.title === ig || f.category === ig)\n )\n : allFindings;\n\n const riskScore = calculateRiskScore(filteredFindings);\n const riskGrade = getRiskGrade(riskScore);\n const findingsCount = countFindings(filteredFindings);\n\n const recommendation =\n riskScore >= 76 ? \"block\" : riskScore >= 26 ? \"warn\" : \"approve\";\n\n const result: ScanResult = {\n skillName: skill.frontmatter.name || \"unknown\",\n skillVersion: skill.frontmatter.version,\n skillSource: \"local\",\n status: \"complete\",\n riskScore,\n riskGrade,\n findingsCount,\n findings: filteredFindings,\n recommendation,\n };\n\n if (!options.skipCache) {\n setCached(content, result);\n }\n\n return result;\n}\n\nexport { parseSkill } from \"./skill-parser.js\";\nexport { runStaticAnalysis } from \"./static-analysis.js\";\nexport { validateMetadata } from \"./metadata-validator.js\";\nexport { checkDependencies } from \"./dependency-checker.js\";\nexport { detectTyposquats } from \"./typosquat-detector.js\";\nexport { calculateRiskScore, getRiskGrade, countFindings } from \"./risk-scorer.js\";\n","import chalk from \"chalk\";\nimport type { ScanResult, Finding, Severity } from \"@clawvet/shared\";\n\nconst SEVERITY_COLORS: Record<Severity, (s: string) => string> = {\n critical: chalk.bgRed.white.bold,\n high: chalk.red.bold,\n medium: chalk.yellow,\n low: chalk.blue,\n};\n\nconst GRADE_COLORS: Record<string, (s: string) => string> = {\n A: chalk.green.bold,\n B: chalk.greenBright,\n C: chalk.yellow.bold,\n D: chalk.redBright.bold,\n F: chalk.bgRed.white.bold,\n};\n\nexport function printScanResult(result: ScanResult): void {\n console.log();\n console.log(chalk.bold(\"━\".repeat(60)));\n console.log(chalk.bold(\" ClawVet Scan Report\"));\n console.log(chalk.bold(\"━\".repeat(60)));\n console.log();\n\n console.log(` Skill: ${chalk.bold(result.skillName)}`);\n if (result.skillVersion) {\n console.log(` Version: ${result.skillVersion}`);\n }\n console.log();\n\n // Risk score\n const gradeColor = GRADE_COLORS[result.riskGrade] || chalk.white;\n console.log(\n ` Risk Score: ${gradeColor(`${result.riskScore}/100`)} Grade: ${gradeColor(result.riskGrade)}`\n );\n console.log();\n\n // Findings summary\n const fc = result.findingsCount;\n console.log(\" Findings:\");\n if (fc.critical)\n console.log(\n ` ${SEVERITY_COLORS.critical(` CRITICAL `)} ${fc.critical}`\n );\n if (fc.high)\n console.log(` ${SEVERITY_COLORS.high(\"HIGH\")} ${fc.high}`);\n if (fc.medium)\n console.log(` ${SEVERITY_COLORS.medium(\"MEDIUM\")} ${fc.medium}`);\n if (fc.low) console.log(` ${SEVERITY_COLORS.low(\"LOW\")} ${fc.low}`);\n if (!fc.critical && !fc.high && !fc.medium && !fc.low) {\n console.log(` ${chalk.green(\"No findings — skill looks clean!\")}`);\n }\n console.log();\n\n // Detailed findings\n if (result.findings.length > 0) {\n console.log(chalk.bold(\" Details:\"));\n console.log();\n for (const f of result.findings) {\n const color = SEVERITY_COLORS[f.severity];\n const confStr = f.confidence != null ? ` ${Math.round(f.confidence * 100)}%` : \"\";\n console.log(` ${color(`[${f.severity.toUpperCase()}${confStr}]`)} ${f.title}`);\n console.log(` ${chalk.dim(f.description)}`);\n if (f.evidence) {\n console.log(` Evidence: ${chalk.italic(f.evidence)}`);\n }\n if (f.lineNumber) {\n console.log(` Line: ${f.lineNumber}`);\n }\n if (f.fix) {\n console.log(` Fix: ${chalk.green(f.fix)}`);\n }\n console.log();\n }\n }\n\n // Recommendation\n const recColors: Record<string, (s: string) => string> = {\n block: chalk.bgRed.white.bold,\n warn: chalk.bgYellow.black.bold,\n approve: chalk.bgGreen.black.bold,\n };\n const rec = result.recommendation || \"approve\";\n console.log(\n ` Recommendation: ${(recColors[rec] || chalk.white)(` ${rec.toUpperCase()} `)}`\n );\n console.log();\n console.log(chalk.bold(\"━\".repeat(60)));\n console.log();\n}\n","import type { ScanResult } from \"@clawvet/shared\";\n\nexport function printJsonResult(result: ScanResult): void {\n console.log(JSON.stringify(result, null, 2));\n}\n","import type { ScanResult, Finding, Severity } from \"@clawvet/shared\";\n\nconst SEVERITY_TO_SARIF: Record<Severity, string> = {\n critical: \"error\",\n high: \"error\",\n medium: \"warning\",\n low: \"note\",\n};\n\nconst SEVERITY_TO_LEVEL: Record<Severity, string> = {\n critical: \"9.0\",\n high: \"7.0\",\n medium: \"4.0\",\n low: \"1.0\",\n};\n\nexport function printSarifResult(result: ScanResult): void {\n const rules = new Map<string, { id: string; finding: Finding }>();\n\n for (const f of result.findings) {\n const ruleId = f.category + \"/\" + f.title.toLowerCase().replace(/[^a-z0-9]+/g, \"-\");\n if (!rules.has(ruleId)) {\n rules.set(ruleId, { id: ruleId, finding: f });\n }\n }\n\n const sarif = {\n $schema: \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json\",\n version: \"2.1.0\",\n runs: [\n {\n tool: {\n driver: {\n name: \"clawvet\",\n informationUri: \"https://github.com/clawvet/clawvet\",\n rules: [...rules.values()].map((r) => ({\n id: r.id,\n shortDescription: { text: r.finding.title },\n fullDescription: { text: r.finding.description },\n defaultConfiguration: {\n level: SEVERITY_TO_SARIF[r.finding.severity],\n },\n properties: {\n security_severity: SEVERITY_TO_LEVEL[r.finding.severity],\n },\n })),\n },\n },\n results: result.findings.map((f) => {\n const ruleId = f.category + \"/\" + f.title.toLowerCase().replace(/[^a-z0-9]+/g, \"-\");\n return {\n ruleId,\n level: SEVERITY_TO_SARIF[f.severity],\n message: {\n text: f.description + (f.evidence ? ` Evidence: ${f.evidence}` : \"\"),\n ...(f.fix ? { markdown: `${f.description}\\n\\n**Fix:** ${f.fix}` } : {}),\n },\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: \"SKILL.md\" },\n region: { startLine: f.lineNumber ?? 1 },\n },\n },\n ],\n };\n }),\n },\n ],\n };\n\n console.log(JSON.stringify(sarif, null, 2));\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir, platform, release } from \"node:os\";\nimport { randomUUID } from \"node:crypto\";\nimport type { ScanResult } from \"@clawvet/shared\";\n\nconst CONFIG_DIR = join(homedir(), \".clawvet\");\nconst CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\nconst TELEMETRY_ENDPOINT = \"https://bazzzz--0ab7a9301f3911f1ab9942dde27851f2.web.val.run\";\n\ninterface Config {\n telemetry?: \"on\" | \"off\" | undefined; // undefined = not yet asked\n deviceId?: string;\n scanCount?: number;\n}\n\nfunction loadConfig(): Config {\n try {\n if (existsSync(CONFIG_FILE)) {\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf-8\"));\n }\n } catch {\n // corrupted config, start fresh\n }\n return {};\n}\n\nfunction saveConfig(config: Config): void {\n try {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n } catch {\n // non-critical, ignore\n }\n}\n\nexport function isTelemetryEnabled(): boolean {\n const env = process.env.CLAWVET_TELEMETRY;\n if (env === \"0\" || env === \"off\") return false;\n if (env === \"1\" || env === \"on\") return true;\n const config = loadConfig();\n return config.telemetry === \"on\";\n}\n\nexport function setTelemetry(enabled: boolean): void {\n const config = loadConfig();\n config.telemetry = enabled ? \"on\" : \"off\";\n saveConfig(config);\n}\n\nexport function hasBeenAsked(): boolean {\n const config = loadConfig();\n return config.telemetry !== undefined;\n}\n\nfunction getDeviceId(): string {\n const config = loadConfig();\n if (!config.deviceId) {\n config.deviceId = randomUUID();\n saveConfig(config);\n }\n return config.deviceId;\n}\n\nfunction incrementScanCount(): number {\n const config = loadConfig();\n config.scanCount = (config.scanCount || 0) + 1;\n saveConfig(config);\n return config.scanCount;\n}\n\nexport function getScanCount(): number {\n return loadConfig().scanCount || 0;\n}\n\nexport function sendTelemetry(result: ScanResult): Promise<void> {\n if (!isTelemetryEnabled()) return Promise.resolve();\n\n const scanCount = incrementScanCount();\n\n const payload = {\n deviceId: getDeviceId(),\n scanCount,\n ts: new Date().toISOString(),\n os: platform(),\n osVersion: release(),\n skillName: result.skillName,\n riskScore: result.riskScore,\n riskGrade: result.riskGrade,\n findingsCount: result.findingsCount,\n cached: result.cached ?? false,\n };\n\n return fetch(TELEMETRY_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: AbortSignal.timeout(3000),\n }).then(() => {}).catch(() => {\n // silently ignore — telemetry is best-effort\n });\n}\n","import { readdirSync, existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { scanSkill } from \"@clawvet/shared\";\nimport { printScanResult } from \"../output/terminal.js\";\nimport chalk from \"chalk\";\n\nconst DEFAULT_SKILL_DIRS = [\n join(homedir(), \".openclaw\", \"skills\"),\n join(homedir(), \".openclaw\", \"workspace\", \"skills\"),\n];\n\nexport async function auditCommand(options: { dir?: string } = {}): Promise<void> {\n const SKILL_DIRS = options.dir ? [options.dir] : DEFAULT_SKILL_DIRS;\n console.log(chalk.bold(\"\\nClawVet Audit — Scanning all installed skills\\n\"));\n\n let totalScanned = 0;\n let totalThreats = 0;\n\n for (const dir of SKILL_DIRS) {\n if (!existsSync(dir)) {\n if (options.dir) {\n console.error(chalk.yellow(`Warning: Directory not found: ${dir}\\n`));\n process.exit(1);\n }\n continue;\n }\n\n // If the dir itself contains a SKILL.md, scan it directly\n const directSkillFile = join(dir, \"SKILL.md\");\n if (existsSync(directSkillFile)) {\n const content = readFileSync(directSkillFile, \"utf-8\");\n const result = await scanSkill(content);\n totalScanned++;\n totalThreats += result.findings.length;\n printScanResult(result);\n continue;\n }\n\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillFile = join(dir, entry.name, \"SKILL.md\");\n if (!existsSync(skillFile)) continue;\n\n const content = readFileSync(skillFile, \"utf-8\");\n const result = await scanSkill(content);\n totalScanned++;\n totalThreats += result.findings.length;\n\n printScanResult(result);\n }\n }\n\n console.log(chalk.bold(`\\nAudit complete: ${totalScanned} skills scanned, ${totalThreats} findings\\n`));\n}\n","import { readFileSync, existsSync, watch } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport chalk from \"chalk\";\nimport { scanSkill } from \"@clawvet/shared\";\nimport { printScanResult } from \"../output/terminal.js\";\n\nconst DEFAULT_SKILL_DIRS = [\n join(homedir(), \".openclaw\", \"skills\"),\n join(homedir(), \".openclaw\", \"workspace\", \"skills\"),\n];\n\nexport async function watchCommand(options: {\n threshold?: number;\n dir?: string;\n}): Promise<void> {\n const threshold = options.threshold || 50;\n const SKILL_DIRS = options.dir ? [options.dir] : DEFAULT_SKILL_DIRS;\n console.log(\n chalk.bold(\n `\\nClawVet Watch — monitoring skill directories (threshold: ${threshold})\\n`\n )\n );\n\n const watchDirs: string[] = [];\n for (const dir of SKILL_DIRS) {\n if (existsSync(dir)) {\n watchDirs.push(dir);\n }\n }\n\n if (watchDirs.length === 0) {\n console.log(\n chalk.yellow(\n \"No OpenClaw skill directories found. Watching will start when directories are created.\\n\"\n )\n );\n console.log(chalk.dim(\"Expected directories:\"));\n for (const dir of SKILL_DIRS) {\n console.log(chalk.dim(` ${dir}`));\n }\n console.log();\n process.exit(1);\n }\n\n console.log(chalk.dim(\"Watching:\"));\n for (const dir of watchDirs) {\n console.log(chalk.dim(` ${dir}`));\n }\n console.log();\n\n for (const dir of watchDirs) {\n const watcher = watch(dir, { recursive: true }, async (event, filename) => {\n if (!filename?.endsWith(\"SKILL.md\")) return;\n\n const skillFile = join(dir, filename);\n if (!existsSync(skillFile)) return;\n\n console.log(chalk.dim(`\\nDetected change: ${filename}`));\n\n try {\n const content = readFileSync(skillFile, \"utf-8\");\n const result = await scanSkill(content);\n\n if (result.cached) {\n console.log(chalk.dim(\"(cached)\"));\n }\n printScanResult(result);\n\n if (result.riskScore > threshold) {\n console.log(\n chalk.bgRed.white.bold(\n ` BLOCKED — Risk score ${result.riskScore} exceeds threshold ${threshold} `\n )\n );\n console.log(\n chalk.red(\n `This skill should not be installed. Run 'clawvet scan ${skillFile}' for details.\\n`\n )\n );\n }\n } catch (err) {\n console.error(chalk.red(`Error scanning ${filename}:`), err);\n }\n });\n\n process.on(\"SIGINT\", () => {\n watcher.close();\n console.log(chalk.dim(\"\\nWatch stopped.\"));\n process.exit(0);\n });\n }\n\n console.log(chalk.dim(\"Press Ctrl+C to stop watching.\\n\"));\n await new Promise(() => {});\n}\n","import { readFileSync, existsSync, statSync } from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { scanSkill } from \"@clawvet/shared\";\nimport type { RiskGrade } from \"@clawvet/shared\";\n\nconst GRADE_COLORS: Record<RiskGrade, string> = {\n A: \"brightgreen\",\n B: \"green\",\n C: \"yellow\",\n D: \"orange\",\n F: \"red\",\n};\n\nconst GRADE_LABELS: Record<RiskGrade, string> = {\n A: \"safe\",\n B: \"safe\",\n C: \"review\",\n D: \"risky\",\n F: \"dangerous\",\n};\n\nexport async function badgeCommand(\n target: string,\n options: { markdown?: boolean }\n): Promise<void> {\n const skillPath = resolve(target);\n let skillFile = skillPath;\n\n if (\n existsSync(skillPath) &&\n !skillPath.endsWith(\".md\") &&\n existsSync(join(skillPath, \"SKILL.md\"))\n ) {\n skillFile = join(skillPath, \"SKILL.md\");\n }\n\n if (!existsSync(skillFile) || statSync(skillFile).isDirectory()) {\n console.error(`Error: Cannot find SKILL.md at ${skillFile}`);\n process.exit(1);\n }\n\n const content = readFileSync(skillFile, \"utf-8\");\n const result = await scanSkill(content);\n\n const label = GRADE_LABELS[result.riskGrade];\n const color = GRADE_COLORS[result.riskGrade];\n const badgeUrl = `https://img.shields.io/badge/clawvet-${result.riskGrade}%20${label}-${color}`;\n const linkUrl = \"https://github.com/MohibShaikh/clawvet\";\n\n if (options.markdown) {\n console.log(`[](${linkUrl})`);\n } else {\n console.log();\n console.log(chalk.bold(\" ClawVet Trust Badge\"));\n console.log();\n console.log(` Skill: ${chalk.bold(result.skillName)}`);\n console.log(` Grade: ${result.riskGrade} (${label})`);\n console.log(` Score: ${result.riskScore}/100`);\n console.log();\n console.log(chalk.dim(\" Markdown (paste in README):\"));\n console.log();\n console.log(` [](${linkUrl})`);\n console.log();\n console.log(chalk.dim(\" HTML:\"));\n console.log();\n console.log(` <a href=\"${linkUrl}\"><img src=\"${badgeUrl}\" alt=\"ClawVet ${result.riskGrade}\"></a>`);\n console.log();\n }\n}\n"],"mappings":"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","names":["readFileSync","existsSync","join","chalk","re","existsSync","join","readFileSync","chalk","resolve","existsSync","readFileSync","join","homedir","chalk","join","homedir","existsSync","readFileSync","readFileSync","existsSync","join","homedir","chalk","DEFAULT_SKILL_DIRS","join","homedir","chalk","existsSync","readFileSync","readFileSync","existsSync","statSync","resolve","join","chalk","GRADE_COLORS","resolve","existsSync","join","statSync","readFileSync","chalk"]}
|
package/package.json
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "clawvet",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "Skill vetting & supply chain security for OpenClaw. Scans SKILL.md files for prompt injection, credential theft, RCE, typosquatting, and social engineering.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"clawvet": "dist/index.js"
|
|
8
|
-
},
|
|
9
|
-
"main": "dist/index.js",
|
|
10
|
-
"types": "dist/index.d.ts",
|
|
11
|
-
"files": [
|
|
12
|
-
"dist",
|
|
13
|
-
"README.md",
|
|
14
|
-
"LICENSE"
|
|
15
|
-
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "tsup",
|
|
18
|
-
"dev": "tsx src/index.ts",
|
|
19
|
-
"prepublishOnly": "npm run build"
|
|
20
|
-
},
|
|
21
|
-
"keywords": [
|
|
22
|
-
"openclaw",
|
|
23
|
-
"clawvet",
|
|
24
|
-
"security",
|
|
25
|
-
"scanner",
|
|
26
|
-
"skill",
|
|
27
|
-
"supply-chain",
|
|
28
|
-
"prompt-injection",
|
|
29
|
-
"ai-agent",
|
|
30
|
-
"malware",
|
|
31
|
-
"cli"
|
|
32
|
-
],
|
|
33
|
-
"license": "MIT",
|
|
34
|
-
"repository": {
|
|
35
|
-
"type": "git",
|
|
36
|
-
"url": "git+https://github.com/MohibShaikh/clawvet.git"
|
|
37
|
-
},
|
|
38
|
-
"homepage": "https://github.com/MohibShaikh/clawvet#readme",
|
|
39
|
-
"bugs": {
|
|
40
|
-
"url": "https://github.com/MohibShaikh/clawvet/issues"
|
|
41
|
-
},
|
|
42
|
-
"dependencies": {
|
|
43
|
-
"chalk": "^5.4.0",
|
|
44
|
-
"commander": "^13.0.0",
|
|
45
|
-
"fastest-levenshtein": "^1.0.16",
|
|
46
|
-
"yaml": "^2.6.0"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@types/node": "^22.0.0",
|
|
50
|
-
"tsup": "^8.5.1",
|
|
51
|
-
"tsx": "^4.19.0",
|
|
52
|
-
"typescript": "^5.7.0"
|
|
53
|
-
},
|
|
54
|
-
"engines": {
|
|
55
|
-
"node": ">=22.0.0"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "clawvet",
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"description": "Skill vetting & supply chain security for OpenClaw. Scans SKILL.md files for prompt injection, credential theft, RCE, typosquatting, and social engineering.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"clawvet": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"dev": "tsx src/index.ts",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"openclaw",
|
|
23
|
+
"clawvet",
|
|
24
|
+
"security",
|
|
25
|
+
"scanner",
|
|
26
|
+
"skill",
|
|
27
|
+
"supply-chain",
|
|
28
|
+
"prompt-injection",
|
|
29
|
+
"ai-agent",
|
|
30
|
+
"malware",
|
|
31
|
+
"cli"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/MohibShaikh/clawvet.git"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/MohibShaikh/clawvet#readme",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/MohibShaikh/clawvet/issues"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"chalk": "^5.4.0",
|
|
44
|
+
"commander": "^13.0.0",
|
|
45
|
+
"fastest-levenshtein": "^1.0.16",
|
|
46
|
+
"yaml": "^2.6.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^22.0.0",
|
|
50
|
+
"tsup": "^8.5.1",
|
|
51
|
+
"tsx": "^4.19.0",
|
|
52
|
+
"typescript": "^5.7.0"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=22.0.0"
|
|
56
|
+
}
|
|
57
|
+
}
|