agent-security-scanner-mcp 3.9.0 → 3.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,11 +8,11 @@ Security scanner for AI coding agents and autonomous assistants. Scans code for
8
8
  [![Benchmark: 97.7% precision](https://img.shields.io/badge/precision-97.7%25-brightgreen.svg)](benchmarks/RESULTS.md)
9
9
  [![CI](https://github.com/sinewaveai/agent-security-scanner-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/sinewaveai/agent-security-scanner-mcp/actions/workflows/test.yml)
10
10
 
11
- > **New in v3.8.0:** Cross-file taint tracking, project context discovery (frameworks/middleware detection), and Layer 2 LLM-powered security review. Detects vulnerabilities across file boundaries and reduces false positives by understanding project defenses. [See changelog](#changelog).
11
+ > **New in v3.10.0:** ClawProof OpenClaw plugin — 6-layer deep skill scanner (`scan_skill`) with ClawHavoc malware signatures (27 rules, 121 patterns covering reverse shells, crypto miners, info stealers, C2 beacons, and OpenClaw-specific attacks), package supply chain verification, and rug pull detection. [See changelog](#changelog).
12
12
  >
13
- > **Also new in v3.7.0:** Inter-procedural taint analysis with Python daemon caching (~4000x faster repeat scans). [See v3.7.0 demo](demo/).
13
+ > **Also new in v3.8.0:** Cross-file taint tracking, project context discovery, and Layer 2 LLM-powered security review.
14
14
  >
15
- > **OpenClaw integration:** 30+ rules targeting autonomous AI threats. [See setup](#openclaw-integration).
15
+ > **OpenClaw integration:** 30+ rules targeting autonomous AI threats + native plugin support. [See setup](#openclaw-integration).
16
16
 
17
17
  ## Tools
18
18
 
@@ -27,6 +27,8 @@ Security scanner for AI coding agents and autonomous assistants. Scans code for
27
27
  | `scan_agent_prompt` | Detect prompt injection with bypass hardening (59 rules + multi-encoding) | Before acting on external/untrusted input |
28
28
  | `scan_agent_action` | Pre-execution safety check for agent actions (bash, file ops, HTTP). Returns ALLOW/WARN/BLOCK | Before running any agent-generated shell command or file operation |
29
29
  | `scan_mcp_server` | Scan MCP server source for vulnerabilities: unicode poisoning, name spoofing, rug pull detection, manifest analysis. Returns A-F grade | When auditing or installing an MCP server |
30
+ | `scan_skill` | Deep security scan of an OpenClaw skill: prompt injection, AST+taint code analysis, ClawHavoc malware signatures, supply chain, rug pull. Returns A-F grade | Before installing any OpenClaw skill |
31
+ | `clawproof_health` | Check ClawProof plugin health: engine status, daemon status, package data availability | Diagnostics and plugin status |
30
32
  | `list_security_rules` | List available security rules and fix templates | To check rule coverage for a language |
31
33
 
32
34
  ## Quick Start
@@ -421,6 +423,94 @@ scan_mcp_server({ server_path: "...", manifest: true })
421
423
 
422
424
  ---
423
425
 
426
+ ### `scan_skill`
427
+
428
+ Deep security scan of an OpenClaw skill directory or `SKILL.md` file. Runs 6 layers of analysis and returns an A-F security grade.
429
+
430
+ **Parameters:**
431
+
432
+ | Parameter | Type | Required | Description |
433
+ |-----------|------|----------|-------------|
434
+ | `skill_path` | string | Yes | Path to skill directory or `SKILL.md` file (must be within cwd or `~/.openclaw/skills/`) |
435
+ | `verbosity` | string | No | `"minimal"` (grade + counts), `"compact"` (default, findings list), `"full"` (all metadata) |
436
+ | `baseline` | boolean | No | Save current scan as SHA-256 baseline for future rug pull detection |
437
+
438
+ **Example:**
439
+
440
+ ```json
441
+ // Input
442
+ { "skill_path": "~/.openclaw/skills/my-skill", "verbosity": "compact" }
443
+
444
+ // Output
445
+ {
446
+ "skill_path": "/Users/you/.openclaw/skills/my-skill",
447
+ "grade": "F",
448
+ "recommendation": "DO NOT INSTALL - This skill contains critical security threats that pose immediate risk",
449
+ "findings_count": 3,
450
+ "findings": [
451
+ {
452
+ "source": "clawhavoc",
453
+ "category": "reverse_shell",
454
+ "severity": "CRITICAL",
455
+ "message": "Bash reverse shell detected — opens interactive shell over TCP",
456
+ "rule_id": "clawhavoc.revshell.bash",
457
+ "confidence": "HIGH"
458
+ }
459
+ ],
460
+ "layers_executed": {
461
+ "L1_prompt": true,
462
+ "L2_code_blocks": true,
463
+ "L3_supporting_files": true,
464
+ "L4_clawhavoc": true,
465
+ "L5_supply_chain": true,
466
+ "L6_rug_pull": true
467
+ }
468
+ }
469
+ ```
470
+
471
+ **6-layer analysis pipeline:**
472
+
473
+ | Layer | What It Checks |
474
+ |-------|---------------|
475
+ | L1 Prompt Scan | 59+ prompt injection rules against skill instructions |
476
+ | L2 Code Blocks | Bash via action scanner; JS/Python/etc via AST+taint analysis |
477
+ | L3 Supporting Files | All code files in the skill directory (capped at 20 files) |
478
+ | L4 ClawHavoc Signatures | 27 malware rules, 121 regex patterns across 10 threat categories |
479
+ | L5 Supply Chain | Package hallucination detection across npm, PyPI, RubyGems, crates, Dart, Perl |
480
+ | L6 Rug Pull | SHA-256 baseline comparison to detect post-install content tampering |
481
+
482
+ **ClawHavoc threat categories:**
483
+
484
+ | Category | Examples |
485
+ |----------|---------|
486
+ | Reverse Shells | Bash `/dev/tcp`, netcat `-e`, Python socket+dup2, Perl/Ruby TCP |
487
+ | Crypto Miners | XMRig, CoinHive, stratum+tcp, WebAssembly miners |
488
+ | Info Stealers | Browser cookies/Login Data, macOS Keychain, Atomic Stealer, RedLine, Lumma/wallet |
489
+ | Keyloggers | CGEventTapCreate, pynput, SetWindowsHookEx, NSEvent.addGlobalMonitor |
490
+ | Screen Capture | Screenshot + upload/webhook combinations |
491
+ | DNS Exfiltration | nslookup/dig with command substitution, base64+DNS |
492
+ | C2 Beacons | Periodic HTTP callbacks (setInterval+fetch, while+requests+sleep) |
493
+ | OpenClaw Attacks | Config theft, SOUL.md tampering, session hijacking, gateway token theft |
494
+ | Campaign Patterns | Webhook exfiltration to known attacker infrastructure |
495
+ | Exfil Endpoints | Known malicious domains and staging servers |
496
+
497
+ **Rug pull workflow:**
498
+
499
+ ```bash
500
+ # 1. On first install — record trusted baseline
501
+ scan_skill({ skill_path: "~/.openclaw/skills/my-skill", baseline: true })
502
+
503
+ # 2. On each subsequent check — detect content changes
504
+ scan_skill({ skill_path: "~/.openclaw/skills/my-skill" })
505
+ # → grade F if any content changed since baseline
506
+ ```
507
+
508
+ **Security notes:**
509
+ - `skill_path` must be within `process.cwd()` or `~/.openclaw/skills/` — symlink escapes are rejected
510
+ - Scan times out at 120 seconds with a grade F on timeout
511
+
512
+ ---
513
+
424
514
  ### `list_security_rules`
425
515
 
426
516
  List all 1700+ security scanning rules and 120 fix templates. Use to understand what vulnerabilities the scanner detects or to check coverage for a specific language or vulnerability type.
@@ -815,12 +905,28 @@ The scanner includes 30+ rules targeting OpenClaw's unique attack surface:
815
905
  | **Unsafe Automation** | "Run hourly without asking", "Disable safety checks" |
816
906
  | **Service Attacks** | "Delete all repos", "Make payment to..." |
817
907
 
908
+ ### Skill Scanning (New in v3.10.0)
909
+
910
+ Before installing any skill from ClawHub or other sources:
911
+
912
+ ```bash
913
+ node index.js scan-skill ~/.openclaw/skills/some-skill
914
+ ```
915
+
916
+ Or via MCP:
917
+ ```json
918
+ { "skill_path": "~/.openclaw/skills/some-skill", "verbosity": "compact" }
919
+ ```
920
+
921
+ Returns grade A-F with findings from 6 layers of analysis. Grade F = do not install.
922
+
818
923
  ### Usage in OpenClaw
819
924
 
820
925
  The skill is auto-discovered. Use it by asking:
821
926
  - "Scan this prompt for security issues"
822
927
  - "Check if this code is safe to run"
823
928
  - "Verify these packages aren't hallucinated"
929
+ - "Scan this skill before I install it"
824
930
 
825
931
  ---
826
932
 
@@ -882,7 +988,7 @@ AI coding agents introduce attack surfaces that traditional security tools weren
882
988
  |----------|-------|
883
989
  | **Transport** | stdio |
884
990
  | **Package** | `agent-security-scanner-mcp` (npm) |
885
- | **Tools** | 10 |
991
+ | **Tools** | 12 |
886
992
  | **Languages** | 12 |
887
993
  | **Ecosystems** | 7 |
888
994
  | **Auth** | None required |
@@ -964,6 +1070,15 @@ All MCP tools support a `verbosity` parameter to minimize context window consump
964
1070
 
965
1071
  ## Changelog
966
1072
 
1073
+ ### v3.10.0
1074
+ - **`scan_skill` Tool** — 6-layer deep security scanner for OpenClaw skills: prompt injection (59+ rules), AST+taint code analysis, ClawHavoc malware signatures, package supply chain verification, and SHA-256 rug pull detection. Returns A-F grade with hard-fail on ClawHavoc/rug pull/critical findings
1075
+ - **ClawHavoc Signature Database** (`rules/clawhavoc.yaml`) — 27 rules, 121 regex patterns across 10 threat categories (reverse shells, crypto miners, info stealers, keyloggers, screen capture, DNS exfiltration, C2 beacons, OpenClaw-specific attacks, campaign patterns, exfil endpoints), mapped to MITRE ATT&CK
1076
+ - **OpenClaw Plugin Skeleton** — Native plugin manifest (`openclaw.plugin.json`), config loader (`~/.openclaw/scanner-config.json`), and health check endpoint (`clawproof_health` MCP tool)
1077
+ - **CLI**: `scan-skill <path>` command with `--baseline` flag; `audit` and `harden` stubs (experimental)
1078
+ - **Security fixes**: Path containment uses `realpathSync` to prevent symlink bypass; dedup key includes `source` to prevent ClawHavoc findings from being suppressed by same-named code_analysis findings
1079
+ - **Bug fix**: SQL injection concat detection now covers JavaScript (was C#-only) — single-quoted and template literal strings now detected
1080
+ - Tests: 462 passed (up from 433, includes 34 scan-skill tests and 14 plugin-integration tests)
1081
+
967
1082
  ### v3.8.0
968
1083
  - **`scan_mcp_server` Tool** - New tool for auditing MCP servers: scans source code for 24+ vulnerability patterns, unicode/homoglyph poisoning, tool name spoofing (Levenshtein distance), description injection, and returns A-F security grade
969
1084
  - **Unicode Poisoning Detection** - Detects zero-width characters (U+200B/C/D, FEFF, 2060), bidirectional override characters (U+202A-202E, 2066-2069), and mixed-script homoglyph substitutions (Cyrillic/ASCII adjacency)
package/index.js CHANGED
@@ -180,6 +180,41 @@ server.tool(
180
180
  scanMcpServer
181
181
  );
182
182
 
183
+ // ===========================================
184
+ // OPENCLAW SKILL SCANNING
185
+ // ===========================================
186
+
187
+ server.tool(
188
+ "scan_skill",
189
+ "Deep security scan of an OpenClaw skill. Multi-layer analysis: prompt injection detection, code analysis (AST+taint), ClawHavoc malware signatures, package supply chain verification, rug pull detection. Returns security grade A-F with detailed findings.",
190
+ {
191
+ skill_path: z.string().describe("Path to skill directory or SKILL.md file"),
192
+ verbosity: z.enum(['minimal', 'compact', 'full']).optional().describe("Response detail level"),
193
+ baseline: z.boolean().optional().describe("Save current scan as baseline for rug pull detection"),
194
+ },
195
+ async ({ skill_path, verbosity, baseline }) => {
196
+ const { scanSkill } = await import('./src/tools/scan-skill.js');
197
+ return scanSkill({ skill_path, verbosity, baseline });
198
+ }
199
+ );
200
+
201
+ // ===========================================
202
+ // PLUGIN HEALTH CHECK
203
+ // ===========================================
204
+
205
+ server.tool(
206
+ "clawproof_health",
207
+ "Check plugin health: engine status, daemon status, package data availability",
208
+ {},
209
+ async () => {
210
+ const { getHealthStatus } = await import('./src/plugin-health.js');
211
+ const health = await getHealthStatus();
212
+ return {
213
+ content: [{ type: "text", text: JSON.stringify(health, null, 2) }]
214
+ };
215
+ }
216
+ );
217
+
183
218
  // ===========================================
184
219
  // CLI COMMANDS - Extracted to src/cli/
185
220
  // ===========================================
@@ -397,6 +432,41 @@ if (cliArgs[0] === 'init') {
397
432
  console.error(JSON.stringify({ error: err.message }));
398
433
  process.exit(1);
399
434
  });
435
+ } else if (cliArgs[0] === 'scan-skill') {
436
+ const skillPath = cliArgs[1];
437
+ if (!skillPath) {
438
+ console.error('Usage: agent-security-scanner-mcp scan-skill <skill-path> [--verbosity minimal|compact|full] [--baseline]');
439
+ process.exit(1);
440
+ }
441
+ const verbosityIdx = cliArgs.indexOf('--verbosity');
442
+ const verbosity = verbosityIdx !== -1 ? cliArgs[verbosityIdx + 1] : 'compact';
443
+ const baseline = cliArgs.includes('--baseline');
444
+
445
+ // Load package lists for supply chain scanning
446
+ const { loadPackageLists } = await import('./src/tools/check-package.js');
447
+ loadPackageLists();
448
+
449
+ const { scanSkill } = await import('./src/tools/scan-skill.js');
450
+ scanSkill({ skill_path: skillPath, verbosity, baseline }).then(result => {
451
+ const output = JSON.parse(result.content[0].text);
452
+ console.log(JSON.stringify(output, null, 2));
453
+ process.exit(output.grade === 'F' || output.grade === 'D' ? 1 : 0);
454
+ }).catch(err => {
455
+ console.error(JSON.stringify({ error: err.message }));
456
+ process.exit(1);
457
+ });
458
+ } else if (cliArgs[0] === 'audit') {
459
+ const { runAudit } = await import('./src/cli/audit.js');
460
+ runAudit(cliArgs.slice(1)).then(() => process.exit(0)).catch(err => {
461
+ console.error(` Error: ${err.message}\n`);
462
+ process.exit(1);
463
+ });
464
+ } else if (cliArgs[0] === 'harden') {
465
+ const { runHarden } = await import('./src/cli/harden.js');
466
+ runHarden(cliArgs.slice(1)).then(() => process.exit(0)).catch(err => {
467
+ console.error(` Error: ${err.message}\n`);
468
+ process.exit(1);
469
+ });
400
470
  } else if (cliArgs[0] === '--help' || cliArgs[0] === '-h' || cliArgs[0] === 'help') {
401
471
  console.log('\n agent-security-scanner-mcp\n');
402
472
  console.log(' Commands:');
@@ -409,12 +479,15 @@ if (cliArgs[0] === 'init') {
409
479
  console.log(' CLI Tools (for scripts & OpenClaw):');
410
480
  console.log(' scan-prompt <text> Scan prompt for injection attacks');
411
481
  console.log(' scan-security <file> Scan file for vulnerabilities');
482
+ console.log(' scan-skill <path> Scan OpenClaw skill for security threats [--baseline]');
412
483
  console.log(' check-package <n> <e> Check if package exists in ecosystem');
413
484
  console.log(' scan-packages <f> <e> Scan file imports for hallucinated packages');
414
485
  console.log(' scan-project <dir> Scan directory for vulnerabilities with grading');
415
486
  console.log(' scan-diff [base] [target] Scan git diff for new vulnerabilities');
416
487
  console.log(' scan-mcp <path> Scan MCP server source for security issues');
417
- console.log(' scan-action <t> <v> Check agent action before execution\n');
488
+ console.log(' scan-action <t> <v> Check agent action before execution');
489
+ console.log(' audit [--config-path] Audit OpenClaw config for security issues [experimental]');
490
+ console.log(' harden [--fix] Auto-harden OpenClaw configuration [experimental]\n');
418
491
  console.log(' (no args) Start MCP server on stdio\n');
419
492
  console.log(' Options:');
420
493
  console.log(' --verbosity <level> minimal|compact|full (default: compact)');
@@ -440,6 +513,13 @@ if (cliArgs[0] === 'init') {
440
513
  await server.connect(transport);
441
514
  console.error("Security Scanner MCP Server running on stdio");
442
515
 
516
+ // Pre-warm daemon in background (non-blocking)
517
+ if (process.env.SCANNER_PREWARM !== '0') {
518
+ import('./src/daemon-client.js').then(({ getDaemonClient }) => {
519
+ getDaemonClient().preWarm().catch(() => {});
520
+ }).catch(() => {});
521
+ }
522
+
443
523
  // Shutdown daemon when MCP server closes
444
524
  server.server.onclose = async () => {
445
525
  await shutdownDaemon();
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "agent-security-scanner",
3
+ "version": "3.9.0",
4
+ "description": "Security scanner for OpenClaw: prompt injection firewall, package hallucination detection, code vulnerability scanning, auto-fix",
5
+ "author": "Sinewave AI",
6
+ "license": "MIT",
7
+ "openclaw": {
8
+ "extensions": ["tools", "skills"],
9
+ "emoji": "shield",
10
+ "permissions": ["fs:read"]
11
+ },
12
+ "tools": [
13
+ {
14
+ "name": "scan_security",
15
+ "description": "Scan a file for security vulnerabilities"
16
+ },
17
+ {
18
+ "name": "scan_agent_prompt",
19
+ "description": "Scan a prompt for injection attacks"
20
+ },
21
+ {
22
+ "name": "check_package",
23
+ "description": "Verify a package is not hallucinated"
24
+ },
25
+ {
26
+ "name": "scan_agent_action",
27
+ "description": "Pre-execution safety check for agent actions"
28
+ },
29
+ {
30
+ "name": "scan_skill",
31
+ "description": "Scan an OpenClaw skill for security threats"
32
+ },
33
+ {
34
+ "name": "clawproof_health",
35
+ "description": "Check plugin health status"
36
+ }
37
+ ],
38
+ "skills": [
39
+ "skills/openclaw/SKILL.md"
40
+ ]
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-security-scanner-mcp",
3
- "version": "3.9.0",
3
+ "version": "3.10.1",
4
4
  "mcpName": "io.github.sinewaveai/agent-security-scanner-mcp",
5
5
  "description": "Security scanner MCP server for AI coding agents. Prompt injection firewall, package hallucination detection (4.3M+ packages), 1000+ vulnerability rules with AST & taint analysis, auto-fix. For Claude Code, Cursor, Windsurf, Cline, OpenClaw.",
6
6
  "main": "index.js",
@@ -90,6 +90,9 @@
90
90
  "src/config.js",
91
91
  "src/history.js",
92
92
  "src/typosquat.js",
93
+ "src/plugin-config.js",
94
+ "src/plugin-health.js",
95
+ "openclaw.plugin.json",
93
96
  "templates/**",
94
97
  "analyzer.py",
95
98
  "ast_parser.py",
package/regex_fallback.py CHANGED
@@ -475,6 +475,8 @@ def _scan_javascript(lines: List[str]) -> List[Dict]:
475
475
 
476
476
  if re.search(r"\bdb\.query\s*\(.*\+\s*\w", line):
477
477
  findings.append(_make_finding("sql-injection", i, line))
478
+ if re.search(r'''(?:["'`])SELECT\b[^"'`]*["'`]\s*\+''', line, re.IGNORECASE):
479
+ findings.append(_make_finding("sql-injection-concat", i, line))
478
480
 
479
481
  if re.search(r"createHash\s*\(\s*['\"]md5['\"]", line, re.IGNORECASE):
480
482
  findings.append(_make_finding("insecure-hash-md5", i, line))
@@ -677,7 +679,7 @@ def _scan_csharp(lines: List[str]) -> List[Dict]:
677
679
  findings.append(_make_finding("sql-injection-sqlcommand", i, line))
678
680
  if re.search(r"\bSqlQuery\b.*\+\s*\w", line):
679
681
  findings.append(_make_finding("sql-injection-sqlquery", i, line))
680
- if re.search(r"\"SELECT\b.*\"\s*\+\s*\w", line, re.IGNORECASE):
682
+ if re.search(r'''(?:["'`])SELECT\b[^"'`]*["'`]\s*\+''', line, re.IGNORECASE):
681
683
  findings.append(_make_finding("sql-injection-concat", i, line))
682
684
  if re.search(r"\bProcess\.Start\s*\(", line):
683
685
  findings.append(_make_finding("command-injection-process-start", i, line))