clawvet 0.2.0 → 0.2.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/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/commands/scan.ts
7
- import { readFileSync, existsSync } from "fs";
7
+ import { readFileSync, existsSync, statSync } from "fs";
8
8
  import { resolve, join } from "path";
9
9
 
10
10
  // ../shared/src/patterns.ts
@@ -730,7 +730,7 @@ function detectTyposquats(skillName) {
730
730
  }
731
731
  }
732
732
  const patterns = [
733
- { re: /-+/, desc: "extra hyphens" },
733
+ { re: /-{2,}/, desc: "extra hyphens" },
734
734
  { re: /(.)\1{2,}/, desc: "repeated characters" }
735
735
  ];
736
736
  for (const p of patterns) {
@@ -892,7 +892,7 @@ function printJsonResult(result) {
892
892
  async function fetchRemoteSkill(slug) {
893
893
  const urls = [
894
894
  `https://raw.githubusercontent.com/openclaw/skills/main/${slug}/SKILL.md`,
895
- `https://clawhub.com/api/v1/skills/${slug}/raw`
895
+ `https://clawhub.ai/api/v1/skills/${slug}/raw`
896
896
  ];
897
897
  for (const url of urls) {
898
898
  try {
@@ -926,13 +926,16 @@ async function scanCommand(target, options) {
926
926
  if (existsSync(skillPath) && !skillPath.endsWith(".md") && existsSync(join(skillPath, "SKILL.md"))) {
927
927
  skillFile = join(skillPath, "SKILL.md");
928
928
  }
929
- if (!existsSync(skillFile)) {
929
+ if (!existsSync(skillFile) || statSync(skillFile).isDirectory()) {
930
930
  console.error(`Error: Cannot find SKILL.md at ${skillFile}`);
931
+ console.error(`Hint: If this is a directory of skills, use 'clawvet audit --dir ${target}' instead.`);
931
932
  process.exit(1);
932
933
  }
933
934
  content = readFileSync(skillFile, "utf-8");
934
935
  }
935
- const result = await scanSkill(content, { semantic: false });
936
+ const result = await scanSkill(content, {
937
+ semantic: options.semantic ?? false
938
+ });
936
939
  if (options.format === "json") {
937
940
  printJsonResult(result);
938
941
  } else {
@@ -955,16 +958,33 @@ import { readdirSync, existsSync as existsSync2, readFileSync as readFileSync2 }
955
958
  import { join as join2 } from "path";
956
959
  import { homedir } from "os";
957
960
  import chalk2 from "chalk";
958
- var SKILL_DIRS = [
961
+ var DEFAULT_SKILL_DIRS = [
959
962
  join2(homedir(), ".openclaw", "skills"),
960
963
  join2(homedir(), ".openclaw", "workspace", "skills")
961
964
  ];
962
- async function auditCommand() {
965
+ async function auditCommand(options = {}) {
966
+ const SKILL_DIRS = options.dir ? [options.dir] : DEFAULT_SKILL_DIRS;
963
967
  console.log(chalk2.bold("\nClawVet Audit \u2014 Scanning all installed skills\n"));
964
968
  let totalScanned = 0;
965
969
  let totalThreats = 0;
966
970
  for (const dir of SKILL_DIRS) {
967
- if (!existsSync2(dir)) continue;
971
+ if (!existsSync2(dir)) {
972
+ if (options.dir) {
973
+ console.error(chalk2.yellow(`Warning: Directory not found: ${dir}
974
+ `));
975
+ process.exit(1);
976
+ }
977
+ continue;
978
+ }
979
+ const directSkillFile = join2(dir, "SKILL.md");
980
+ if (existsSync2(directSkillFile)) {
981
+ const content = readFileSync2(directSkillFile, "utf-8");
982
+ const result = await scanSkill(content);
983
+ totalScanned++;
984
+ totalThreats += result.findings.length;
985
+ printScanResult(result);
986
+ continue;
987
+ }
968
988
  const entries = readdirSync(dir, { withFileTypes: true });
969
989
  for (const entry of entries) {
970
990
  if (!entry.isDirectory()) continue;
@@ -987,12 +1007,13 @@ import { readFileSync as readFileSync3, existsSync as existsSync3, watch } from
987
1007
  import { join as join3 } from "path";
988
1008
  import { homedir as homedir2 } from "os";
989
1009
  import chalk3 from "chalk";
990
- var SKILL_DIRS2 = [
1010
+ var DEFAULT_SKILL_DIRS2 = [
991
1011
  join3(homedir2(), ".openclaw", "skills"),
992
1012
  join3(homedir2(), ".openclaw", "workspace", "skills")
993
1013
  ];
994
1014
  async function watchCommand(options) {
995
1015
  const threshold = options.threshold || 50;
1016
+ const SKILL_DIRS = options.dir ? [options.dir] : DEFAULT_SKILL_DIRS2;
996
1017
  console.log(
997
1018
  chalk3.bold(
998
1019
  `
@@ -1001,7 +1022,7 @@ ClawVet Watch \u2014 monitoring skill directories (threshold: ${threshold})
1001
1022
  )
1002
1023
  );
1003
1024
  const watchDirs = [];
1004
- for (const dir of SKILL_DIRS2) {
1025
+ for (const dir of SKILL_DIRS) {
1005
1026
  if (existsSync3(dir)) {
1006
1027
  watchDirs.push(dir);
1007
1028
  }
@@ -1013,11 +1034,11 @@ ClawVet Watch \u2014 monitoring skill directories (threshold: ${threshold})
1013
1034
  )
1014
1035
  );
1015
1036
  console.log(chalk3.dim("Expected directories:"));
1016
- for (const dir of SKILL_DIRS2) {
1037
+ for (const dir of SKILL_DIRS) {
1017
1038
  console.log(chalk3.dim(` ${dir}`));
1018
1039
  }
1019
1040
  console.log();
1020
- return;
1041
+ process.exit(1);
1021
1042
  }
1022
1043
  console.log(chalk3.dim("Watching:"));
1023
1044
  for (const dir of watchDirs) {
@@ -1065,7 +1086,7 @@ Detected change: ${filename}`));
1065
1086
 
1066
1087
  // src/index.ts
1067
1088
  var program = new Command();
1068
- program.name("clawvet").description("Skill vetting & supply chain security for OpenClaw").version("0.2.0");
1089
+ program.name("clawvet").description("Skill vetting & supply chain security for OpenClaw").version("0.2.3");
1069
1090
  program.command("scan").description("Scan a skill for security threats").argument("<target>", "Path to skill folder or SKILL.md file").option("--format <format>", "Output format: terminal or json", "terminal").option("--fail-on <severity>", "Exit 1 if findings at this severity or above").option("--semantic", "Enable AI semantic analysis (requires ANTHROPIC_API_KEY)").option("--remote", "Fetch skill from ClawHub by name instead of local path").action(async (target, opts) => {
1070
1091
  await scanCommand(target, {
1071
1092
  format: opts.format,
@@ -1074,11 +1095,11 @@ program.command("scan").description("Scan a skill for security threats").argumen
1074
1095
  remote: opts.remote
1075
1096
  });
1076
1097
  });
1077
- program.command("audit").description("Scan all installed OpenClaw skills").action(async () => {
1078
- await auditCommand();
1098
+ program.command("audit").description("Scan all installed OpenClaw skills").option("--dir <path>", "Custom skills directory to scan").action(async (opts) => {
1099
+ await auditCommand({ dir: opts.dir });
1079
1100
  });
1080
- program.command("watch").description("Pre-install hook \u2014 blocks risky skill installs").option("--threshold <score>", "Risk score threshold (default 50)", "50").action(async (opts) => {
1081
- await watchCommand({ threshold: parseInt(opts.threshold) });
1101
+ program.command("watch").description("Pre-install hook \u2014 blocks risky skill installs").option("--threshold <score>", "Risk score threshold (default 50)", "50").option("--dir <path>", "Custom skills directory to watch").action(async (opts) => {
1102
+ await watchCommand({ threshold: parseInt(opts.threshold), dir: opts.dir });
1082
1103
  });
1083
1104
  program.parse();
1084
1105
  //# sourceMappingURL=index.js.map
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/index.ts","../src/output/terminal.ts","../src/output/json.ts","../src/commands/audit.ts","../src/commands/watch.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { scanCommand } from \"./commands/scan.js\";\nimport { auditCommand } from \"./commands/audit.js\";\nimport { watchCommand } from \"./commands/watch.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"clawvet\")\n .description(\"Skill vetting & supply chain security for OpenClaw\")\n .version(\"0.2.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 or json\", \"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 .action(async (target, opts) => {\n await scanCommand(target, {\n format: opts.format,\n failOn: opts.failOn,\n semantic: opts.semantic,\n remote: opts.remote,\n });\n });\n\nprogram\n .command(\"audit\")\n .description(\"Scan all installed OpenClaw skills\")\n .action(async () => {\n await auditCommand();\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 .action(async (opts) => {\n await watchCommand({ threshold: parseInt(opts.threshold) });\n });\n\nprogram.parse();\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport { scanSkill } from \"@clawvet/shared\";\nimport { printScanResult } from \"../output/terminal.js\";\nimport { printJsonResult } from \"../output/json.js\";\n\nexport interface ScanOptions {\n format?: \"terminal\" | \"json\";\n failOn?: \"critical\" | \"high\" | \"medium\" | \"low\";\n semantic?: boolean;\n remote?: 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.com/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)) {\n console.error(`Error: Cannot find SKILL.md at ${skillFile}`);\n process.exit(1);\n }\n\n content = readFileSync(skillFile, \"utf-8\");\n }\n\n const result = await scanSkill(content, { semantic: false });\n\n if (options.format === \"json\") {\n printJsonResult(result);\n } else {\n printScanResult(result);\n }\n\n if (options.failOn) {\n const severityOrder = [\"low\", \"medium\", \"high\", \"critical\"];\n const threshold = severityOrder.indexOf(options.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\nexport const THREAT_PATTERNS: ThreatPattern[] = [\n // ═══════════════════════════════════════════════════════\n // CRITICAL: Remote code execution\n // ═══════════════════════════════════════════════════════\n {\n name: \"CURL_PIPE_BASH\",\n pattern: /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 },\n {\n name: \"WGET_EXECUTE\",\n pattern: /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 },\n {\n name: \"EVAL_DYNAMIC\",\n pattern: /eval\\s*\\(/gi,\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Dynamic eval() usage\",\n description: \"Uses eval() which can execute arbitrary code.\",\n },\n {\n name: \"BASE64_DECODE\",\n pattern: /base64\\s+(-d|--decode)/gi,\n severity: \"critical\",\n category: \"obfuscation\",\n title: \"Base64 decode execution\",\n description: \"Decodes base64 content, often used to hide malicious payloads.\",\n },\n {\n name: \"PYTHON_EXEC\",\n pattern: /python[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 },\n {\n name: \"REVERSE_SHELL\",\n pattern: /\\/dev\\/tcp\\/|nc\\s+-[elp]|ncat\\s+-|mkfifo\\s+.*\\/tmp/gi,\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Reverse shell\",\n description: \"Creates a reverse shell connection back to an attacker-controlled server.\",\n },\n {\n name: \"CRON_PERSISTENCE\",\n pattern: /crontab\\s+-|\\/etc\\/cron|systemctl\\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 },\n {\n name: \"PERL_EXEC\",\n pattern: /perl\\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 },\n {\n name: \"NODE_EVAL\",\n pattern: /node\\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 },\n {\n name: \"RUBY_EXEC\",\n pattern: /ruby\\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\n {\n name: \"RAW_SOCKET\",\n pattern: /new\\s+Socket|net\\.connect|dgram\\.createSocket/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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\n\n // ═══════════════════════════════════════════════════════\n // LOW: Suspicious but not necessarily malicious\n // ═══════════════════════════════════════════════════════\n {\n name: \"SHELL_EXEC\",\n pattern: /child_process|exec\\(|spawn\\(/gi,\n severity: \"low\",\n category: \"code_execution\",\n title: \"Shell execution API\",\n description: \"Uses shell execution APIs — legitimate but worth noting.\",\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 },\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 },\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 },\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 },\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 },\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 = /^---\\n([\\s\\S]*?)\\n---/;\nconst CODE_BLOCK_RE = /```(\\w*)\\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 } from \"../types.js\";\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 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 });\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 });\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 });\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 });\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 });\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 });\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 });\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 });\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 });\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: /-+/, 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];\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 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\";\n\nexport interface ScanOptions {\n semantic?: boolean;\n semanticAnalyzer?: (content: string) => Promise<Finding[]>;\n}\n\nexport async function scanSkill(\n content: string,\n options: ScanOptions = {}\n): Promise<ScanResult> {\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 const riskScore = calculateRiskScore(allFindings);\n const riskGrade = getRiskGrade(riskScore);\n const findingsCount = countFindings(allFindings);\n\n const recommendation =\n riskScore >= 76 ? \"block\" : riskScore >= 26 ? \"warn\" : \"approve\";\n\n return {\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: allFindings,\n recommendation,\n };\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 console.log(` ${color(`[${f.severity.toUpperCase()}]`)} ${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 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 { 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 SKILL_DIRS = [\n join(homedir(), \".openclaw\", \"skills\"),\n join(homedir(), \".openclaw\", \"workspace\", \"skills\"),\n];\n\nexport async function auditCommand(): Promise<void> {\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)) continue;\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 SKILL_DIRS = [\n join(homedir(), \".openclaw\", \"skills\"),\n join(homedir(), \".openclaw\", \"workspace\", \"skills\"),\n];\n\nexport async function watchCommand(options: {\n threshold?: number;\n}): Promise<void> {\n const threshold = options.threshold || 50;\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 return;\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 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"],"mappings":"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","names":["existsSync","readFileSync","join","chalk","join","existsSync","readFileSync","readFileSync","existsSync","join","homedir","chalk","SKILL_DIRS","join","homedir","chalk","existsSync","readFileSync"]}
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/index.ts","../src/output/terminal.ts","../src/output/json.ts","../src/commands/audit.ts","../src/commands/watch.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { scanCommand } from \"./commands/scan.js\";\nimport { auditCommand } from \"./commands/audit.js\";\nimport { watchCommand } from \"./commands/watch.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"clawvet\")\n .description(\"Skill vetting & supply chain security for OpenClaw\")\n .version(\"0.2.3\");\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 or json\", \"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 .action(async (target, opts) => {\n await scanCommand(target, {\n format: opts.format,\n failOn: opts.failOn,\n semantic: opts.semantic,\n remote: opts.remote,\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.parse();\n","import { readFileSync, existsSync, statSync } from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport { scanSkill } from \"@clawvet/shared\";\nimport { printScanResult } from \"../output/terminal.js\";\nimport { printJsonResult } from \"../output/json.js\";\n\nexport interface ScanOptions {\n format?: \"terminal\" | \"json\";\n failOn?: \"critical\" | \"high\" | \"medium\" | \"low\";\n semantic?: boolean;\n remote?: 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 const result = await scanSkill(content, {\n semantic: options.semantic ?? false,\n });\n\n if (options.format === \"json\") {\n printJsonResult(result);\n } else {\n printScanResult(result);\n }\n\n if (options.failOn) {\n const severityOrder = [\"low\", \"medium\", \"high\", \"critical\"];\n const threshold = severityOrder.indexOf(options.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\nexport const THREAT_PATTERNS: ThreatPattern[] = [\n // ═══════════════════════════════════════════════════════\n // CRITICAL: Remote code execution\n // ═══════════════════════════════════════════════════════\n {\n name: \"CURL_PIPE_BASH\",\n pattern: /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 },\n {\n name: \"WGET_EXECUTE\",\n pattern: /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 },\n {\n name: \"EVAL_DYNAMIC\",\n pattern: /eval\\s*\\(/gi,\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Dynamic eval() usage\",\n description: \"Uses eval() which can execute arbitrary code.\",\n },\n {\n name: \"BASE64_DECODE\",\n pattern: /base64\\s+(-d|--decode)/gi,\n severity: \"critical\",\n category: \"obfuscation\",\n title: \"Base64 decode execution\",\n description: \"Decodes base64 content, often used to hide malicious payloads.\",\n },\n {\n name: \"PYTHON_EXEC\",\n pattern: /python[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 },\n {\n name: \"REVERSE_SHELL\",\n pattern: /\\/dev\\/tcp\\/|nc\\s+-[elp]|ncat\\s+-|mkfifo\\s+.*\\/tmp/gi,\n severity: \"critical\",\n category: \"remote_code_execution\",\n title: \"Reverse shell\",\n description: \"Creates a reverse shell connection back to an attacker-controlled server.\",\n },\n {\n name: \"CRON_PERSISTENCE\",\n pattern: /crontab\\s+-|\\/etc\\/cron|systemctl\\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 },\n {\n name: \"PERL_EXEC\",\n pattern: /perl\\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 },\n {\n name: \"NODE_EVAL\",\n pattern: /node\\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 },\n {\n name: \"RUBY_EXEC\",\n pattern: /ruby\\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\n {\n name: \"RAW_SOCKET\",\n pattern: /new\\s+Socket|net\\.connect|dgram\\.createSocket/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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\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 },\n\n // ═══════════════════════════════════════════════════════\n // LOW: Suspicious but not necessarily malicious\n // ═══════════════════════════════════════════════════════\n {\n name: \"SHELL_EXEC\",\n pattern: /child_process|exec\\(|spawn\\(/gi,\n severity: \"low\",\n category: \"code_execution\",\n title: \"Shell execution API\",\n description: \"Uses shell execution APIs — legitimate but worth noting.\",\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 },\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 },\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 },\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 },\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 },\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 = /^---\\n([\\s\\S]*?)\\n---/;\nconst CODE_BLOCK_RE = /```(\\w*)\\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 } from \"../types.js\";\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 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 });\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 });\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 });\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 });\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 });\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 });\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 });\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 });\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 });\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];\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 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\";\n\nexport interface ScanOptions {\n semantic?: boolean;\n semanticAnalyzer?: (content: string) => Promise<Finding[]>;\n}\n\nexport async function scanSkill(\n content: string,\n options: ScanOptions = {}\n): Promise<ScanResult> {\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 const riskScore = calculateRiskScore(allFindings);\n const riskGrade = getRiskGrade(riskScore);\n const findingsCount = countFindings(allFindings);\n\n const recommendation =\n riskScore >= 76 ? \"block\" : riskScore >= 26 ? \"warn\" : \"approve\";\n\n return {\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: allFindings,\n recommendation,\n };\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 console.log(` ${color(`[${f.severity.toUpperCase()}]`)} ${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 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 { 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 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"],"mappings":"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","names":["existsSync","readFileSync","join","chalk","join","existsSync","readFileSync","readFileSync","existsSync","join","homedir","chalk","DEFAULT_SKILL_DIRS","join","homedir","chalk","existsSync","readFileSync"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawvet",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "description": "Skill vetting & supply chain security for OpenClaw. Scans SKILL.md files for prompt injection, credential theft, RCE, typosquatting, and social engineering.",
5
5
  "type": "module",
6
6
  "bin": {