skill-security-scanner 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,6 +12,7 @@
12
12
  | `scan-all` | Security scan every skill in the project |
13
13
  | `lint <skill>` | Validate SKILL.md frontmatter schema |
14
14
  | `lint --all` | Validate every skill in the project |
15
+ | `info <skill>` | Pretty-print parsed frontmatter for debugging |
15
16
 
16
17
  ---
17
18
 
@@ -147,7 +148,7 @@ npx skill-security-scanner lint --all --strict
147
148
  ### Lint Output Example
148
149
 
149
150
  ```
150
- Lint — voiceover-bot
151
+ 🔎 Lint — voiceover-bot
151
152
  ──────────────────────────────────────────────────
152
153
  Status: ❌ FAIL
153
154
 
@@ -161,6 +162,63 @@ Warnings (1)
161
162
 
162
163
  ---
163
164
 
165
+ ## `info` — Frontmatter Inspector
166
+
167
+ Pretty-prints everything the scanner sees when it parses a skill's `SKILL.md`. Useful for debugging mismatches between what you wrote and what the tool reads.
168
+
169
+ ```bash
170
+ npx skill-security-scanner info frontend-design
171
+ npx skill-security-scanner info .agent/skills/voiceover-bot
172
+
173
+ # Machine-readable output
174
+ npx skill-security-scanner info frontend-design --json
175
+ ```
176
+
177
+ ### What It Shows
178
+
179
+ | Section | Details |
180
+ |---|---|
181
+ | **📦 Identity** | `name`, `description`, `version`, resolved path |
182
+ | **🔐 Permissions** | Each scope color-coded by risk — 🚨 high, ⚠️ med, ✅ low |
183
+ | **🗂️ Requires** | `bin` (flags dangerous entries), `env` (flags sensitive names), `config` |
184
+ | **⚡ Command Dispatch** | Registered command → handler mappings |
185
+
186
+ ### Info Flags
187
+
188
+ | Flag | Description |
189
+ |---|---|
190
+ | `--json` | Output `{ path, frontmatter }` as JSON |
191
+
192
+ ### Info Output Example
193
+
194
+ ```
195
+ 📦 Skill Info — voiceover-bot
196
+ ──────────────────────────────────────────────────────
197
+ Name voiceover-bot
198
+ Description Converts text to speech using ElevenLabs
199
+ Version 1.2.0
200
+ Path /project/.agent/skills/voiceover-bot
201
+
202
+ 🔐 Permissions
203
+ 🚨 shell:execute
204
+ ⚠️ network:outbound
205
+ ✅ file_system:read
206
+
207
+ 🗂️ Requires
208
+ bin:
209
+ ⚠ curl (dangerous)
210
+ • ffmpeg
211
+ env:
212
+ 🔑 ELEVENLABS_API_KEY (sensitive)
213
+ • VOICE_ID
214
+
215
+ ⚡ Command Dispatch
216
+ speak → scripts/speak.sh
217
+ list-voices → scripts/list.py
218
+ ```
219
+
220
+ ---
221
+
164
222
  ## Install Globally
165
223
 
166
224
  ```bash
@@ -170,6 +228,7 @@ npm install -g skill-security-scanner
170
228
  skill-security-scanner frontend-design
171
229
  skill-security-scanner lint --all
172
230
  skill-security-scanner scan-all
231
+ skill-security-scanner info frontend-design
173
232
  ```
174
233
 
175
234
  ## CI / GitHub Actions
@@ -184,5 +243,4 @@ skill-security-scanner scan-all
184
243
 
185
244
  ## Upgrade
186
245
 
187
- Free tier covers static analysis + linting. For **dynamic sandboxing**, **GitHub org scans**, and **CI dashboards**:
188
-
246
+ Free tier covers static analysis + linting. For **dynamic sandboxing**, **GitHub org scans**, and **CI dashboards**: → skill-security.com
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -472,6 +472,126 @@ program
472
472
  if (hasFail)
473
473
  process.exit(1);
474
474
  });
475
+ // ── Command: info ────────────────────────────
476
+ program
477
+ .command('info <skill>')
478
+ .description('Pretty-print parsed frontmatter for a skill (permissions, bins, env vars, command-dispatch)')
479
+ .option('--json', 'Output as JSON')
480
+ .action((skill, opts) => {
481
+ const resolvedDir = resolveSkillDir(skill);
482
+ if (!resolvedDir) {
483
+ console.error(chalk_1.default.red(`❌ Skill not found: "${skill}"`));
484
+ console.error(chalk_1.default.gray(' Try: skill-security-scanner info frontend-design'));
485
+ process.exit(1);
486
+ }
487
+ const skillPath = path_1.default.join(resolvedDir, 'SKILL.md');
488
+ if (!fs_1.default.existsSync(skillPath)) {
489
+ console.error(chalk_1.default.red('❌ No SKILL.md found — is this an OpenClaw skill directory?'));
490
+ process.exit(1);
491
+ }
492
+ const content = fs_1.default.readFileSync(skillPath, 'utf8');
493
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/m);
494
+ if (!fmMatch) {
495
+ console.error(chalk_1.default.red('❌ No YAML frontmatter block found in SKILL.md.'));
496
+ console.error(chalk_1.default.gray(' Expected a --- ... --- block at the top of the file.'));
497
+ process.exit(1);
498
+ }
499
+ let fm = {};
500
+ try {
501
+ fm = (js_yaml_1.default.load(fmMatch[1]) ?? {});
502
+ }
503
+ catch (e) {
504
+ const msg = e instanceof Error ? e.message : String(e);
505
+ console.error(chalk_1.default.red(`❌ YAML parse error: ${msg}`));
506
+ process.exit(1);
507
+ }
508
+ if (opts.json) {
509
+ console.log(JSON.stringify({ path: resolvedDir, frontmatter: fm }, null, 2));
510
+ return;
511
+ }
512
+ // ── Identity ──
513
+ console.log('');
514
+ console.log(chalk_1.default.bold.white(`📦 Skill Info — ${fm.name ?? path_1.default.basename(resolvedDir)}`));
515
+ console.log(chalk_1.default.gray('─'.repeat(54)));
516
+ console.log(` ${chalk_1.default.bold('Name')} ${fm.name ? chalk_1.default.cyan(fm.name) : chalk_1.default.gray('(not set)')}`);
517
+ console.log(` ${chalk_1.default.bold('Description')} ${fm.description ? chalk_1.default.white(fm.description) : chalk_1.default.gray('(not set)')}`);
518
+ console.log(` ${chalk_1.default.bold('Version')} ${fm.version ? chalk_1.default.cyan(fm.version) : chalk_1.default.gray('(not set)')}`);
519
+ console.log(` ${chalk_1.default.bold('Path')} ${chalk_1.default.gray(resolvedDir)}`);
520
+ console.log('');
521
+ // ── Permissions ──
522
+ const perms = fm.permissions ?? [];
523
+ console.log(chalk_1.default.bold.white('🔐 Permissions'));
524
+ if (!perms.length) {
525
+ console.log(chalk_1.default.gray(' (none declared)'));
526
+ }
527
+ else {
528
+ const PERM_RISK = {
529
+ 'shell:execute': 'high',
530
+ 'process:spawn': 'high',
531
+ 'file_system:*': 'med',
532
+ 'file_system:write': 'med',
533
+ 'network:outbound': 'med',
534
+ 'network:*': 'med',
535
+ 'file_system:read': 'low',
536
+ 'network:inbound': 'low',
537
+ 'memory:read': 'low',
538
+ 'memory:write': 'low',
539
+ };
540
+ const RISK_COLOR = { high: chalk_1.default.red, med: chalk_1.default.yellow, low: chalk_1.default.green };
541
+ const RISK_ICON = { high: '🚨', med: '⚠️ ', low: '✅' };
542
+ for (const p of perms) {
543
+ const risk = PERM_RISK[p] ?? 'low';
544
+ const color = RISK_COLOR[risk];
545
+ const icon = RISK_ICON[risk];
546
+ console.log(` ${icon} ${color(p)}`);
547
+ }
548
+ }
549
+ console.log('');
550
+ // ── Requires ──
551
+ const bins = fm.requires?.bin ?? [];
552
+ const envs = fm.requires?.env ?? [];
553
+ const configs = fm.requires?.config ?? [];
554
+ console.log(chalk_1.default.bold.white('🗂️ Requires'));
555
+ if (!bins.length && !envs.length && !configs.length) {
556
+ console.log(chalk_1.default.gray(' (none declared)'));
557
+ }
558
+ else {
559
+ if (bins.length) {
560
+ console.log(chalk_1.default.bold(' bin:'));
561
+ for (const b of bins) {
562
+ const isDangerous = DANGEROUS_BINS.includes(b.toLowerCase());
563
+ console.log(` ${isDangerous ? chalk_1.default.red(`⚠ ${b} ${chalk_1.default.italic('(dangerous)')}`) : chalk_1.default.white(`• ${b}`)}`);
564
+ }
565
+ }
566
+ if (envs.length) {
567
+ console.log(chalk_1.default.bold(' env:'));
568
+ const SENSITIVE_RE = /key|secret|token|password|credential|api/i;
569
+ for (const e of envs) {
570
+ const isSensitive = SENSITIVE_RE.test(e);
571
+ console.log(` ${isSensitive ? chalk_1.default.yellow(`🔑 ${e} ${chalk_1.default.italic('(sensitive)')}`) : chalk_1.default.white(`• ${e}`)}`);
572
+ }
573
+ }
574
+ if (configs.length) {
575
+ console.log(chalk_1.default.bold(' config:'));
576
+ configs.forEach(c => console.log(chalk_1.default.white(` • ${c}`)));
577
+ }
578
+ }
579
+ console.log('');
580
+ // ── Command-dispatch ──
581
+ const dispatch = fm['command-dispatch'] ?? {};
582
+ const dispatchEntries = Object.entries(dispatch);
583
+ console.log(chalk_1.default.bold.white('⚡ Command Dispatch'));
584
+ if (!dispatchEntries.length) {
585
+ console.log(chalk_1.default.gray(' (none declared)'));
586
+ }
587
+ else {
588
+ const maxKey = Math.max(...dispatchEntries.map(([k]) => k.length));
589
+ for (const [cmd, handler] of dispatchEntries) {
590
+ console.log(` ${chalk_1.default.cyan(cmd.padEnd(maxKey))} → ${chalk_1.default.white(handler)}`);
591
+ }
592
+ }
593
+ console.log('');
594
+ });
475
595
  // ── Command: scan-all ─────────────────────────
476
596
  program
477
597
  .command('scan-all')
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,16 @@
1
1
  {
2
2
  "name": "skill-security-scanner",
3
- "version": "0.1.1",
4
- "description": "Static security scanner for OpenClaw skill directories",
3
+ "version": "0.1.3",
4
+ "description": "Static security scanner and linter for OpenClaw skill directories",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "skill-security-scanner": "dist/index.js"
8
8
  },
9
+ "files": [
10
+ "dist/",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
9
14
  "scripts": {
10
15
  "build": "tsc",
11
16
  "dev": "ts-node src/index.ts",
@@ -18,13 +23,11 @@
18
23
  "skill",
19
24
  "scanner",
20
25
  "ai-agent",
21
- "cli"
26
+ "cli",
27
+ "lint",
28
+ "static-analysis"
22
29
  ],
23
30
  "license": "MIT",
24
- "repository": {
25
- "type": "git",
26
- "url": "https://github.com/yourorg/skill-security-scanner"
27
- },
28
31
  "dependencies": {
29
32
  "chalk": "^5.3.0",
30
33
  "commander": "^12.1.0",
package/TODO.md DELETED
@@ -1,57 +0,0 @@
1
- # skill-security-scanner — CLI Roadmap
2
-
3
- > Free tier features only. SaaS (dynamic analysis, GitHub Actions, CI dashboards) tracked separately.
4
-
5
- ---
6
-
7
- ## 🗂️ Skill Metadata & Quality
8
-
9
- - [x] **`lint <skill>`** — Validate SKILL.md frontmatter against OpenClaw schema (required fields: `name`, `description`, `version`). Exit 1 on missing fields.
10
- - [ ] **`info <skill>`** — Pretty-print parsed frontmatter (permissions, bins, env vars, command-dispatch). Useful for debugging what the scanner actually sees.
11
- - [ ] **`diff <skill-a> <skill-b>`** — Side-by-side comparison of permissions, requires.bin, and risk scores between two skills or two versions.
12
- - [ ] **`stats`** — Project-wide health snapshot: most common permissions, most used bins, avg finding count per skill, riskiest skill.
13
-
14
- ---
15
-
16
- ## 🔍 Deeper Static Analysis
17
-
18
- - [ ] **Entropy-based secret detection** — Flag high-entropy strings that look like secrets even without a known prefix (e.g. base64 blobs, random hex). Supplement existing regex checks.
19
- - [ ] **License check** — Scan `package.json` / `requirements.txt` for non-commercial or copyleft licenses (GPL, AGPL). Flag as MED risk.
20
- - [ ] **Dead code detection** — Find files in the skill dir never referenced by any other file. Flags bloat and unnecessary attack surface.
21
- - [ ] **Import graph** — List all external packages a skill actually imports and flag ones not declared in frontmatter `requires`.
22
- - [ ] **`--depth <n>`** flag — Control how many levels deep the code scanner recurses (default: 3).
23
-
24
- ---
25
-
26
- ## 🛠️ Developer UX
27
-
28
- - [ ] **`fix --dry-run`** — Suggest auto-fixable issues with diffs shown. E.g. overly broad `file_system:*` → suggest `file_system:read`.
29
- - [ ] **`watch <skill>`** — Re-scan on file save. Live feedback while authoring a skill.
30
- - [ ] **`init`** — Scaffold a compliant `SKILL.md` with correct frontmatter structure and placeholder values.
31
- - [ ] **`--ignore <rule-id>`** — Suppress specific finding by ID inline (e.g. `# sss-ignore: exec-pattern` in source).
32
- - [ ] **`.sss.yaml` config file** — Project-level config: ignored rules, custom dangerous bins list, custom secret regex patterns, default `--fail-on` level.
33
-
34
- ---
35
-
36
- ## 📊 Reporting & Output
37
-
38
- - [ ] **`--output <file>`** — Write full report to disk. Support `.json`, `.md`, and `.sarif` extensions (auto-detected from extension).
39
- - [ ] **Markdown report** — `scan-all --output report.md` generates a formatted table suitable for pasting into PR descriptions.
40
- - [ ] **SARIF output** — `--format sarif` for GitHub Code Scanning and VS Code Problems panel integration.
41
-
42
- ---
43
-
44
- ## Priority Order
45
-
46
- | Priority | Feature | Effort |
47
- |---|---|---|
48
- | 🔴 1 | `lint` command | Low |
49
- | 🔴 2 | `--ignore` + `.sss.yaml` config | Medium |
50
- | 🟡 3 | Entropy-based secret detection | Medium |
51
- | 🟡 4 | `--output report.md` | Low |
52
- | 🟢 5 | `diff` command | Medium |
53
- | 🟢 6 | `stats` command | Low |
54
- | 🟢 7 | `watch` mode | Medium |
55
- | ⚪ 8 | Import graph | High |
56
- | ⚪ 9 | Dead code detection | High |
57
- | ⚪ 10 | SARIF output | Medium |
package/src/index.ts DELETED
@@ -1,660 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import chalk from 'chalk';
4
- import ora from 'ora';
5
- import yaml from 'js-yaml';
6
- import fs from 'fs';
7
- import path from 'path';
8
- import { execSync } from 'child_process';
9
-
10
- // ──────────────────────────────────────────────
11
- // Types
12
- // ──────────────────────────────────────────────
13
- type RiskLevel = 'low' | 'med' | 'high';
14
-
15
- interface Finding {
16
- level: RiskLevel;
17
- message: string;
18
- }
19
-
20
- interface ScanReport {
21
- skill: string;
22
- score: RiskLevel;
23
- findings: Finding[];
24
- badge: string;
25
- upgrade: string;
26
- }
27
-
28
- interface Frontmatter {
29
- name?: string;
30
- description?: string;
31
- version?: string;
32
- permissions?: string[];
33
- requires?: {
34
- env?: string[];
35
- config?: string[];
36
- bin?: string[];
37
- };
38
- 'command-dispatch'?: Record<string, string>;
39
- }
40
-
41
- type LintSeverity = 'error' | 'warn';
42
-
43
- interface LintIssue {
44
- severity: LintSeverity;
45
- field: string;
46
- message: string;
47
- }
48
-
49
- interface LintResult {
50
- skill: string;
51
- passed: boolean;
52
- issues: LintIssue[];
53
- }
54
-
55
- // ──────────────────────────────────────────────
56
- // Risk Checks
57
- // ──────────────────────────────────────────────
58
-
59
- const DANGEROUS_BINS = ['curl', 'wget', 'nc', 'ncat', 'ssh', 'scp', 'rsync', 'python', 'python3', 'bash', 'sh'];
60
- const SECRET_PATTERNS = [
61
- /api[_-]?key\s*[:=]\s*["']?[A-Za-z0-9_\-]{16,}/i,
62
- /secret\s*[:=]\s*["']?[A-Za-z0-9_\-]{16,}/i,
63
- /token\s*[:=]\s*["']?[A-Za-z0-9_\-]{20,}/i,
64
- /password\s*[:=]\s*["']?[A-Za-z0-9@#$!%^&*_\-]{8,}/i,
65
- /sk-[A-Za-z0-9]{32,}/, // OpenAI key
66
- /ghp_[A-Za-z0-9]{36}/, // GitHub PAT
67
- /AKIA[0-9A-Z]{16}/, // AWS Access Key
68
- ];
69
- const EXEC_PATTERNS = /\b(eval|exec|execSync|spawn|spawnSync|child_process)\s*\(/g;
70
- const NETWORK_PATTERNS = /\b(fetch|axios|http\.get|http\.request|https\.get|https\.request|got\(|request\()\s*\(/g;
71
-
72
- function checkPermissions(fm: Frontmatter): Finding[] {
73
- const findings: Finding[] = [];
74
- const perms = fm.permissions ?? [];
75
-
76
- if (perms.some(p => p.includes('file_system:*') || p === 'file_system:write')) {
77
- findings.push({ level: 'med', message: 'Broad file_system write permission — verify scope is intentional' });
78
- }
79
- if (perms.some(p => p.includes('network:*') || p === 'network:outbound')) {
80
- findings.push({ level: 'med', message: 'Outbound network permission detected — review data exfiltration risk' });
81
- }
82
- if (perms.some(p => p.includes('shell:execute') || p.includes('process:spawn'))) {
83
- findings.push({ level: 'high', message: 'Shell/process execution permission — high privilege escalation risk' });
84
- }
85
- return findings;
86
- }
87
-
88
- function checkDangerousBins(fm: Frontmatter): Finding[] {
89
- const bins = fm.requires?.bin ?? [];
90
- return bins
91
- .filter(b => DANGEROUS_BINS.includes(b.toLowerCase()))
92
- .map(b => ({ level: 'high' as RiskLevel, message: `Requires dangerous binary: ${b} (network/exfil risk)` }));
93
- }
94
-
95
- function checkExposedEnv(fm: Frontmatter): Finding[] {
96
- const envVars = fm.requires?.env ?? [];
97
- const sensitivePatterns = /key|secret|token|password|credential|api/i;
98
- return envVars
99
- .filter(e => sensitivePatterns.test(e))
100
- .map(e => ({ level: 'med' as RiskLevel, message: `Sensitive env var required: ${e}` }));
101
- }
102
-
103
- function collectSourceFiles(dir: string): string[] {
104
- const exts = ['.ts', '.js', '.py', '.sh', '.bash'];
105
- const results: string[] = [];
106
-
107
- function walk(current: string) {
108
- for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
109
- const full = path.join(current, entry.name);
110
- if (entry.isDirectory() && !['node_modules', '.git', 'dist'].includes(entry.name)) {
111
- walk(full);
112
- } else if (entry.isFile() && exts.includes(path.extname(entry.name))) {
113
- results.push(full);
114
- }
115
- }
116
- }
117
-
118
- walk(dir);
119
- return results;
120
- }
121
-
122
- function checkCodeRisks(dir: string): Finding[] {
123
- const findings: Finding[] = [];
124
- const files = collectSourceFiles(dir);
125
-
126
- for (const file of files) {
127
- const content = fs.readFileSync(file, 'utf8');
128
- const rel = path.relative(dir, file);
129
-
130
- if (EXEC_PATTERNS.test(content)) {
131
- findings.push({ level: 'high', message: `eval/exec found in ${rel} — remote code execution risk` });
132
- }
133
- if (NETWORK_PATTERNS.test(content)) {
134
- findings.push({ level: 'med', message: `Network call found in ${rel} — verify destination is safe` });
135
- }
136
- for (const pattern of SECRET_PATTERNS) {
137
- if (pattern.test(content)) {
138
- findings.push({ level: 'high', message: `Possible hardcoded secret in ${rel}` });
139
- break;
140
- }
141
- }
142
-
143
- // Reset stateful regexes
144
- EXEC_PATTERNS.lastIndex = 0;
145
- NETWORK_PATTERNS.lastIndex = 0;
146
- }
147
-
148
- return findings;
149
- }
150
-
151
- function checkDependencyVulns(dir: string, skipAudit = false): Finding[] {
152
- const findings: Finding[] = [];
153
- const pkgPath = path.join(dir, 'package.json');
154
- if (!fs.existsSync(pkgPath) || skipAudit) return findings;
155
-
156
- try {
157
- const auditOutput = execSync('npm audit --json', { cwd: dir, timeout: 5_000, stdio: ['pipe', 'pipe', 'pipe'] }).toString();
158
- const audit = JSON.parse(auditOutput);
159
- const vulnCount: number = audit?.metadata?.vulnerabilities?.total ?? 0;
160
- const high: number = (audit?.metadata?.vulnerabilities?.high ?? 0) + (audit?.metadata?.vulnerabilities?.critical ?? 0);
161
-
162
- if (high > 0) findings.push({ level: 'high', message: `${high} high/critical npm vulnerabilities found — run npm audit fix` });
163
- else if (vulnCount > 0) findings.push({ level: 'med', message: `${vulnCount} moderate npm vulnerabilities found` });
164
- } catch {
165
- // npm not available, no lock file, or timed out — skip silently
166
- }
167
-
168
- return findings;
169
- }
170
-
171
- // ──────────────────────────────────────────────
172
- // Score Calculation
173
- // ──────────────────────────────────────────────
174
-
175
- function calculateScore(findings: Finding[]): RiskLevel {
176
- if (findings.some(f => f.level === 'high')) return 'high';
177
- if (findings.some(f => f.level === 'med')) return 'med';
178
- return 'low';
179
- }
180
-
181
-
182
- // ──────────────────────────────────────────────
183
- // Path Resolution
184
- // ──────────────────────────────────────────────
185
-
186
- /** Walk up from `startDir` looking for a directory named `folderName`. */
187
- function findAncestorDir(startDir: string, folderName: string): string | null {
188
- let current = startDir;
189
- for (let i = 0; i < 8; i++) {
190
- const candidate = path.join(current, folderName);
191
- if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) return candidate;
192
- const parent = path.dirname(current);
193
- if (parent === current) break;
194
- current = parent;
195
- }
196
- return null;
197
- }
198
-
199
- /**
200
- * Resolve the skill directory from user input.
201
- * Priority:
202
- * 1. Exact path (absolute or relative) → use as-is
203
- * 2. Walk up looking for `.agent/skills/<input>` or `agent/skills/<input>`
204
- * 3. Walk up looking for any `skills/<input>` folder
205
- */
206
- function resolveSkillDir(input: string): string | null {
207
- const exact = path.resolve(input);
208
- if (fs.existsSync(exact)) return exact;
209
-
210
- const name = path.basename(input); // support "frontend-design" or "skills/frontend-design"
211
- const agentFolders = ['.agent', 'agent', '_agent', '_agents'];
212
-
213
- for (const agentFolder of agentFolders) {
214
- const agentDir = findAncestorDir(process.cwd(), agentFolder);
215
- if (!agentDir) continue;
216
-
217
- const candidate = path.join(agentDir, 'skills', name);
218
- if (fs.existsSync(candidate)) return candidate;
219
-
220
- // also try the input as a sub-path inside agentDir
221
- const subCandidate = path.join(agentDir, input);
222
- if (fs.existsSync(subCandidate)) return subCandidate;
223
- }
224
-
225
- return null;
226
- }
227
-
228
- // ──────────────────────────────────────────────
229
- // Shared scan helper
230
- // ──────────────────────────────────────────────
231
-
232
- interface SkillScanResult {
233
- name: string;
234
- dir: string;
235
- score: RiskLevel;
236
- findings: Finding[];
237
- }
238
-
239
- function scanSkill(skillDir: string, skipAudit = false): SkillScanResult {
240
- const skillPath = path.join(skillDir, 'SKILL.md');
241
- const content = fs.existsSync(skillPath) ? fs.readFileSync(skillPath, 'utf8') : '';
242
- const fmMatch = content.match(/^---\n([\s\S]*?)\n---/m);
243
-
244
- let frontmatter: Frontmatter = {};
245
- try {
246
- frontmatter = (yaml.load(fmMatch?.[1] ?? '') ?? {}) as Frontmatter;
247
- } catch {
248
- // malformed YAML — treat as unparseable, flag it
249
- }
250
-
251
- const findings: Finding[] = [
252
- ...checkPermissions(frontmatter),
253
- ...checkDangerousBins(frontmatter),
254
- ...checkExposedEnv(frontmatter),
255
- ...checkCodeRisks(skillDir),
256
- ...checkDependencyVulns(skillDir, skipAudit),
257
- ];
258
-
259
- if (!fmMatch) {
260
- findings.push({ level: 'low', message: 'No YAML frontmatter found in SKILL.md' });
261
- }
262
-
263
- return {
264
- name: frontmatter.name ?? path.basename(skillDir),
265
- dir: skillDir,
266
- score: calculateScore(findings),
267
- findings,
268
- };
269
- }
270
-
271
-
272
- /** Find all immediate subdirectories of `skillsDir` that contain a SKILL.md */
273
- function discoverSkillDirs(skillsDir: string): string[] {
274
- if (!fs.existsSync(skillsDir)) return [];
275
- return fs.readdirSync(skillsDir, { withFileTypes: true })
276
- .filter(e => e.isDirectory())
277
- .map(e => path.join(skillsDir, e.name))
278
- .filter(d => fs.existsSync(path.join(d, 'SKILL.md')));
279
- }
280
-
281
- // ──────────────────────────────────────────────
282
- // Lint
283
- // ──────────────────────────────────────────────
284
-
285
- const SEMVER_RE = /^\d+\.\d+\.\d+(-[\w.]+)?(\+[\w.]+)?$/;
286
- const PERMISSION_SCOPES = [
287
- 'file_system:read', 'file_system:write', 'file_system:*',
288
- 'network:inbound', 'network:outbound', 'network:*',
289
- 'shell:execute', 'process:spawn', 'memory:read', 'memory:write',
290
- ];
291
-
292
- function lintSkill(skillDir: string): LintResult {
293
- const skillPath = path.join(skillDir, 'SKILL.md');
294
- const issues: LintIssue[] = [];
295
- const skillName = path.basename(skillDir);
296
-
297
- // ── File existence ──
298
- if (!fs.existsSync(skillPath)) {
299
- return { skill: skillName, passed: false, issues: [{ severity: 'error', field: 'SKILL.md', message: 'File not found' }] };
300
- }
301
-
302
- const content = fs.readFileSync(skillPath, 'utf8');
303
- const fmMatch = content.match(/^---\n([\s\S]*?)\n---/m);
304
-
305
- if (!fmMatch) {
306
- return { skill: skillName, passed: false, issues: [{ severity: 'error', field: 'frontmatter', message: 'No YAML frontmatter block found (expected --- ... ---)' }] };
307
- }
308
-
309
- let fm: Frontmatter = {};
310
- try {
311
- fm = (yaml.load(fmMatch[1]) ?? {}) as Frontmatter;
312
- } catch (e: unknown) {
313
- const msg = e instanceof Error ? e.message : String(e);
314
- return { skill: skillName, passed: false, issues: [{ severity: 'error', field: 'frontmatter', message: `YAML parse error: ${msg}` }] };
315
- }
316
-
317
- // ── Required fields ──
318
- if (!fm.name) {
319
- issues.push({ severity: 'error', field: 'name', message: 'Missing required field' });
320
- } else if (typeof fm.name !== 'string') {
321
- issues.push({ severity: 'error', field: 'name', message: 'Must be a string' });
322
- } else if (fm.name.trim().length < 3) {
323
- issues.push({ severity: 'error', field: 'name', message: 'Too short (min 3 chars)' });
324
- }
325
-
326
- if (!fm.description) {
327
- issues.push({ severity: 'error', field: 'description', message: 'Missing required field' });
328
- } else if (typeof fm.description !== 'string') {
329
- issues.push({ severity: 'error', field: 'description', message: 'Must be a string' });
330
- } else if (fm.description.trim().length < 10) {
331
- issues.push({ severity: 'warn', field: 'description', message: 'Very short description (min 10 chars recommended)' });
332
- }
333
-
334
- if (!fm.version) {
335
- issues.push({ severity: 'error', field: 'version', message: 'Missing required field' });
336
- } else if (!SEMVER_RE.test(String(fm.version))) {
337
- issues.push({ severity: 'error', field: 'version', message: `"${fm.version}" is not valid semver (expected x.y.z)` });
338
- }
339
-
340
- // ── Optional field validation ──
341
- if (fm.permissions !== undefined) {
342
- if (!Array.isArray(fm.permissions)) {
343
- issues.push({ severity: 'error', field: 'permissions', message: 'Must be an array of strings' });
344
- } else {
345
- fm.permissions.forEach((p, i) => {
346
- if (typeof p !== 'string') {
347
- issues.push({ severity: 'error', field: `permissions[${i}]`, message: 'Each permission must be a string' });
348
- } else if (!PERMISSION_SCOPES.includes(p)) {
349
- issues.push({ severity: 'warn', field: `permissions[${i}]`, message: `Unknown permission scope "${p}" — check OpenClaw docs` });
350
- }
351
- });
352
- }
353
- }
354
-
355
- if (fm.requires !== undefined) {
356
- if (typeof fm.requires !== 'object' || Array.isArray(fm.requires)) {
357
- issues.push({ severity: 'error', field: 'requires', message: 'Must be an object with optional env/config/bin arrays' });
358
- } else {
359
- for (const key of ['env', 'config', 'bin'] as const) {
360
- const val = fm.requires[key];
361
- if (val !== undefined && !Array.isArray(val)) {
362
- issues.push({ severity: 'error', field: `requires.${key}`, message: 'Must be an array of strings' });
363
- }
364
- }
365
- }
366
- }
367
-
368
- // ── Description quality hints ──
369
- const body = content.slice(content.indexOf('---', 3) + 3).trim();
370
- if (body.length < 50) {
371
- issues.push({ severity: 'warn', field: 'SKILL.md body', message: 'Skill body is very short — consider adding usage examples or detailed instructions' });
372
- }
373
-
374
- const errors = issues.filter(i => i.severity === 'error');
375
- return { skill: fm.name ?? skillName, passed: errors.length === 0, issues };
376
- }
377
-
378
- // ──────────────────────────────────────────────
379
- // CLI
380
- // ──────────────────────────────────────────────
381
-
382
- const program = new Command();
383
-
384
- program
385
- .name('skill-security-scanner')
386
- .description('Static security scanner for OpenClaw skill directories')
387
- .version('0.1.0');
388
-
389
- // ── Command: scan (single skill) ──────────────
390
-
391
- program
392
- .command('scan [dir]', { isDefault: true })
393
- .description('Scan a single skill directory (default command)')
394
- .option('--json', 'Output results as JSON (for CI pipelines)')
395
- .option('--badge', 'Print Markdown badge to stdout')
396
- .action(async (dir: string | undefined, opts: { json?: boolean; badge?: boolean }) => {
397
- if (!dir) {
398
- console.error(chalk.red('❌ Missing skill name or path.'));
399
- console.error(chalk.gray(' Usage: skill-security-scanner <name>'));
400
- console.error(chalk.gray(' Example: skill-security-scanner frontend-design'));
401
- console.error(chalk.gray(' Scan all: skill-security-scanner scan-all'));
402
- process.exit(1);
403
- }
404
-
405
- const resolvedDir = resolveSkillDir(dir);
406
-
407
- if (!resolvedDir) {
408
- console.error(chalk.red(`❌ Skill not found: "${dir}"`));
409
- console.error(chalk.gray(' Try: skill-security-scanner frontend-design'));
410
- console.error(chalk.gray(' Or: skill-security-scanner .agent/skills/frontend-design'));
411
- process.exit(1);
412
- }
413
-
414
- if (!fs.existsSync(path.join(resolvedDir, 'SKILL.md'))) {
415
- console.error(chalk.red('❌ No SKILL.md found — is this an OpenClaw skill directory?'));
416
- process.exit(1);
417
- }
418
-
419
- const spinner = ora('Scanning skill...').start();
420
- const result = scanSkill(resolvedDir);
421
- spinner.stop();
422
-
423
- const BADGE_COLOR_MAP: Record<RiskLevel, string> = { low: 'brightgreen', med: 'yellow', high: 'red' };
424
- const badgeLabel = result.score.toUpperCase();
425
- const badge = `![Skill Security: ${badgeLabel}](https://img.shields.io/badge/Skill%20Security-${badgeLabel}-${BADGE_COLOR_MAP[result.score]}?style=flat-square&logo=shield)`;
426
- const upgrade = 'Full dynamic analysis, GitHub Action & CI dashboards → skill-security.com (7-day free trial)';
427
-
428
- const report: ScanReport = {
429
- skill: result.name, score: result.score, findings: result.findings, badge,
430
- upgrade: ''
431
- };
432
-
433
- if (opts.json) { console.log(JSON.stringify(report, null, 2)); return; }
434
-
435
- const scoreColor = { low: chalk.green, med: chalk.yellow, high: chalk.red }[result.score];
436
- const icon = { low: '✅', med: '⚠️', high: '🚨' }[result.score];
437
- const printGroup = (level: RiskLevel, label: string, color: { bold: (s: string) => string } & ((s: string) => string)) => {
438
- const group = result.findings.filter(f => f.level === level);
439
- if (!group.length) return;
440
- console.log(color.bold(`${label} (${group.length})`));
441
- group.forEach(f => console.log(color(` • ${f.message}`)));
442
- console.log('');
443
- };
444
-
445
- console.log('');
446
- console.log(chalk.bold.white(`🔍 Skill Security Scanner — ${result.name}`));
447
- console.log(chalk.gray('─'.repeat(50)));
448
- console.log(`Risk Score: ${scoreColor(`${icon} ${result.score.toUpperCase()}`)}`);
449
- console.log('');
450
-
451
- if (!result.findings.length) {
452
- console.log(chalk.green('✅ No issues found. Skill looks clean.'));
453
- } else {
454
- printGroup('high', '🚨 HIGH RISK', chalk.red);
455
- printGroup('med', '⚠️ MEDIUM RISK', chalk.yellow);
456
- printGroup('low', '💡 LOW RISK', chalk.gray);
457
- }
458
-
459
- if (opts.badge) { console.log(chalk.gray('Badge:\n')); console.log(badge); console.log(''); }
460
- console.log(chalk.blueBright(`💡 ${upgrade}`));
461
- console.log('');
462
- if (result.score === 'high') process.exit(1);
463
- });
464
-
465
- // ── Command: lint ────────────────────────────
466
-
467
- program
468
- .command('lint [dir]')
469
- .description('Validate SKILL.md frontmatter against the OpenClaw schema')
470
- .option('--json', 'Output results as JSON')
471
- .option('--strict', 'Treat warnings as errors (exit 1)')
472
- .option('--all', 'Lint every skill in the project')
473
- .action((dir: string | undefined, opts: { json?: boolean; strict?: boolean; all?: boolean }) => {
474
- // ── lint --all shortcut ──
475
- if (opts.all || !dir) {
476
- const agentFolders = ['.agent', 'agent', '_agent', '_agents'];
477
- let skillsDir: string | null = null;
478
- for (const folder of agentFolders) {
479
- const agentDir = findAncestorDir(process.cwd(), folder);
480
- if (agentDir) {
481
- const c = path.join(agentDir, 'skills');
482
- if (fs.existsSync(c)) { skillsDir = c; break; }
483
- }
484
- }
485
- if (!skillsDir) {
486
- console.error(chalk.red('❌ No .agent/skills directory found.'));
487
- process.exit(1);
488
- }
489
- const dirs = discoverSkillDirs(skillsDir);
490
- const results = dirs.map(d => lintSkill(d));
491
-
492
- if (opts.json) { console.log(JSON.stringify(results, null, 2)); }
493
- else {
494
- const passed = results.filter(r => r.passed && !(opts.strict && r.issues.some(i => i.severity === 'warn')));
495
- const failed = results.filter(r => !r.passed || (opts.strict && r.issues.some(i => i.severity === 'warn')));
496
- console.log('');
497
- console.log(chalk.bold.white(`🔎 Lint — ${results.length} skills`));
498
- console.log(chalk.gray('─'.repeat(60)));
499
- for (const r of [...failed, ...passed]) {
500
- const ok = !failed.includes(r);
501
- console.log(ok ? chalk.green(` ✅ ${r.skill}`) : chalk.red(` ❌ ${r.skill}`));
502
- r.issues.forEach(issue => {
503
- const c = issue.severity === 'error' ? chalk.red : chalk.yellow;
504
- console.log(c(` [${issue.severity.toUpperCase()}] ${issue.field}: ${issue.message}`));
505
- });
506
- }
507
- console.log(chalk.gray('─'.repeat(60)));
508
- console.log(` ${chalk.green(`✅ ${passed.length} passed`)} ${chalk.red(`❌ ${failed.length} failed`)}`);
509
- console.log('');
510
- }
511
- const anyFailed = results.some(r => !r.passed || (opts.strict && r.issues.some(i => i.severity === 'warn')));
512
- if (anyFailed) process.exit(1);
513
- return;
514
- }
515
-
516
- // ── single skill ──
517
- const resolvedDir = resolveSkillDir(dir);
518
- if (!resolvedDir) {
519
- console.error(chalk.red(`❌ Skill not found: "${dir}"`));
520
- process.exit(1);
521
- }
522
-
523
- const result = lintSkill(resolvedDir);
524
- const hasFail = !result.passed || (opts.strict && result.issues.some(i => i.severity === 'warn'));
525
-
526
- if (opts.json) { console.log(JSON.stringify(result, null, 2)); }
527
- else {
528
- const errors = result.issues.filter(i => i.severity === 'error');
529
- const warns = result.issues.filter(i => i.severity === 'warn');
530
- const statusIcon = hasFail ? '❌' : '✅';
531
- const statusText = hasFail ? chalk.red('FAIL') : chalk.green('PASS');
532
-
533
- console.log('');
534
- console.log(chalk.bold.white(`🔎 Lint — ${result.skill}`));
535
- console.log(chalk.gray('─'.repeat(50)));
536
- console.log(`Status: ${statusIcon} ${statusText}`);
537
- console.log('');
538
-
539
- if (!result.issues.length) {
540
- console.log(chalk.green('✅ All fields valid. Skill looks well-formed.'));
541
- } else {
542
- if (errors.length) {
543
- console.log(chalk.red.bold(`Errors (${errors.length})`));
544
- errors.forEach(i => console.log(chalk.red(` • [${i.field}] ${i.message}`)));
545
- console.log('');
546
- }
547
- if (warns.length) {
548
- console.log(chalk.yellow.bold(`Warnings (${warns.length})`));
549
- warns.forEach(i => console.log(chalk.yellow(` • [${i.field}] ${i.message}`)));
550
- console.log('');
551
- }
552
- }
553
- }
554
-
555
- if (hasFail) process.exit(1);
556
- });
557
-
558
- // ── Command: scan-all ─────────────────────────
559
-
560
- program
561
- .command('scan-all')
562
- .description('Scan every skill in the project and show a summary table')
563
- .option('--json', 'Output results as JSON array')
564
- .option('--fail-on <level>', 'Exit code 1 if any skill reaches this level (low|med|high)', 'high')
565
- .option('--skip-audit', 'Skip npm audit (much faster for large projects)')
566
- .action(async (opts: { json?: boolean; failOn: RiskLevel; skipAudit?: boolean }) => {
567
- const agentFolders = ['.agent', 'agent', '_agent', '_agents'];
568
- let skillsDir: string | null = null;
569
-
570
- for (const folder of agentFolders) {
571
- const agentDir = findAncestorDir(process.cwd(), folder);
572
- if (agentDir) {
573
- const candidate = path.join(agentDir, 'skills');
574
- if (fs.existsSync(candidate)) { skillsDir = candidate; break; }
575
- }
576
- }
577
-
578
- if (!skillsDir) {
579
- console.error(chalk.red('❌ No .agent/skills directory found from the current location.'));
580
- process.exit(1);
581
- }
582
-
583
- const skillDirs = discoverSkillDirs(skillsDir);
584
-
585
- if (!skillDirs.length) {
586
- console.error(chalk.yellow('⚠️ No skill directories with SKILL.md found.'));
587
- process.exit(0);
588
- }
589
-
590
- // Auto-skip audit for large projects unless explicitly requested
591
- const skipAudit = opts.skipAudit ?? skillDirs.length > 5;
592
- const spinner = ora(`Scanning ${skillDirs.length} skills${skipAudit ? ' (audit skipped)' : ''}...`).start();
593
- const results: SkillScanResult[] = skillDirs.map(d => scanSkill(d, skipAudit));
594
- spinner.stop();
595
-
596
- if (opts.json) {
597
- console.log(JSON.stringify(results.map(r => ({
598
- skill: r.name, score: r.score, findingCount: r.findings.length, findings: r.findings,
599
- })), null, 2));
600
- const hasFailure = results.some(r => r.score === opts.failOn || (opts.failOn === 'low' && true) || (opts.failOn === 'med' && r.score !== 'low'));
601
- if (hasFailure) process.exit(1);
602
- return;
603
- }
604
-
605
- // ── Summary table ──
606
- const counts = { high: 0, med: 0, low: 0 };
607
- results.forEach(r => counts[r.score]++);
608
-
609
- const SCORE_COLOR = { low: chalk.green, med: chalk.yellow, high: chalk.red };
610
- const SCORE_ICON = { low: '✅', med: '⚠️ ', high: '🚨' };
611
- const FIND_COLOR = { low: chalk.gray, med: chalk.yellow, high: chalk.red };
612
-
613
- // Sort: high first, then med, then low
614
- const sorted = [...results].sort((a, b) => {
615
- const order: Record<RiskLevel, number> = { high: 0, med: 1, low: 2 };
616
- return order[a.score] - order[b.score];
617
- });
618
-
619
- console.log('');
620
- console.log(chalk.bold.white(`🔍 Skill Security Scanner — Project Scan (${results.length} skills)`));
621
- console.log(chalk.gray('─'.repeat(60)));
622
-
623
- for (const r of sorted) {
624
- const color = SCORE_COLOR[r.score];
625
- const icon = SCORE_ICON[r.score];
626
-
627
- if (!r.findings.length) {
628
- console.log(` ${icon} ${color(r.score.toUpperCase().padEnd(5))} ${r.name}`);
629
- } else {
630
- // Header row for this skill
631
- console.log(` ${icon} ${color(r.score.toUpperCase().padEnd(5))} ${chalk.bold(r.name)}`);
632
-
633
- // Print findings grouped by severity
634
- for (const level of ['high', 'med', 'low'] as RiskLevel[]) {
635
- const group = r.findings.filter(f => f.level === level);
636
- group.forEach(f => {
637
- console.log(` ${FIND_COLOR[level](`→ [${f.level.toUpperCase()}] ${f.message}`)}`);
638
- });
639
- }
640
- console.log('');
641
- }
642
- }
643
-
644
- console.log(chalk.gray('─'.repeat(60)));
645
- console.log(
646
- ` ${chalk.red(`🚨 ${counts.high} HIGH`)} ` +
647
- `${chalk.yellow(`⚠️ ${counts.med} MED`)} ` +
648
- `${chalk.green(`✅ ${counts.low} LOW`)}`
649
- );
650
- console.log('');
651
- // console.log(chalk.blueBright('Full dynamic analysis, GitHub Action & CI dashboards → skill-security.com (7-day free trial)'));
652
- console.log('');
653
-
654
- const LEVEL_ORDER: Record<RiskLevel, number> = { low: 0, med: 1, high: 2 };
655
- const shouldFail = results.some(r => LEVEL_ORDER[r.score] >= LEVEL_ORDER[opts.failOn]);
656
- if (shouldFail) process.exit(1);
657
- });
658
-
659
- program.parse();
660
-
package/tsconfig.json DELETED
@@ -1,25 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "commonjs",
5
- "lib": [
6
- "ES2022"
7
- ],
8
- "outDir": "dist",
9
- "rootDir": "src",
10
- "strict": true,
11
- "esModuleInterop": true,
12
- "skipLibCheck": true,
13
- "declaration": true,
14
- "declarationMap": true,
15
- "sourceMap": true,
16
- "resolveJsonModule": true
17
- },
18
- "include": [
19
- "src/**/*"
20
- ],
21
- "exclude": [
22
- "node_modules",
23
- "dist"
24
- ]
25
- }