shellward 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/install.sh ADDED
@@ -0,0 +1,201 @@
1
+ #!/bin/bash
2
+ # ShellWard One-Click Installer / 一键安装脚本
3
+ # Usage: curl -fsSL https://raw.githubusercontent.com/jnMetaCode/shellward/main/install.sh | bash
4
+
5
+ set -e
6
+
7
+ # Colors
8
+ RED='\033[0;31m'
9
+ GREEN='\033[0;32m'
10
+ YELLOW='\033[1;33m'
11
+ BLUE='\033[0;34m'
12
+ CYAN='\033[0;36m'
13
+ NC='\033[0m'
14
+
15
+ # Detect language
16
+ is_zh() {
17
+ local lang="${LANG:-}${LANGUAGE:-}${LC_ALL:-}"
18
+ [[ "$lang" == *zh* ]]
19
+ }
20
+
21
+ if is_zh; then
22
+ MSG_BANNER="🛡️ ShellWard 安全插件 一键安装"
23
+ MSG_CHECKING="正在检查环境..."
24
+ MSG_NODE_MISSING="❌ 未找到 Node.js (需要 v18+)。请先安装: https://nodejs.org"
25
+ MSG_NODE_OLD="❌ Node.js 版本过低 (当前: %s, 需要: v18+)。请升级: https://nodejs.org"
26
+ MSG_NODE_OK="✅ Node.js %s"
27
+ MSG_OC_MISSING="❌ 未找到 OpenClaw。请先安装: npm install -g openclaw"
28
+ MSG_OC_OK="✅ OpenClaw %s"
29
+ MSG_INSTALLING="正在安装 ShellWard..."
30
+ MSG_ALREADY="⚠️ ShellWard 已安装,正在更新..."
31
+ MSG_CLONE="正在下载 ShellWard..."
32
+ MSG_NPM="通过 npm 安装..."
33
+ MSG_REGISTER="正在注册插件..."
34
+ MSG_SUCCESS="🎉 安装成功!"
35
+ MSG_VERIFY="验证安装..."
36
+ MSG_USAGE="使用方法:"
37
+ MSG_CMD1=" openclaw agent --local -m \"你好\" # 启动安全防护的 Agent"
38
+ MSG_CMD2=" /security # 查看安全状态"
39
+ MSG_CMD3=" /audit # 查看审计日志"
40
+ MSG_CMD4=" /harden # 安全扫描"
41
+ MSG_DOCS="文档: https://github.com/jnMetaCode/shellward"
42
+ MSG_MODE_TITLE="选择安装方式:"
43
+ MSG_MODE_1=" 1) npm 安装 (推荐,自动更新)"
44
+ MSG_MODE_2=" 2) 源码安装 (离线可用)"
45
+ MSG_MODE_PROMPT="请输入 [1/2] (默认 1): "
46
+ MSG_DONE="安装完成!ShellWard 将在下次启动 OpenClaw 时自动加载。"
47
+ MSG_CONFIG="配置文件 (可选):"
48
+ else
49
+ MSG_BANNER="🛡️ ShellWard Security Plugin — One-Click Install"
50
+ MSG_CHECKING="Checking environment..."
51
+ MSG_NODE_MISSING="❌ Node.js not found (v18+ required). Install: https://nodejs.org"
52
+ MSG_NODE_OLD="❌ Node.js too old (current: %s, need: v18+). Upgrade: https://nodejs.org"
53
+ MSG_NODE_OK="✅ Node.js %s"
54
+ MSG_OC_MISSING="❌ OpenClaw not found. Install: npm install -g openclaw"
55
+ MSG_OC_OK="✅ OpenClaw %s"
56
+ MSG_INSTALLING="Installing ShellWard..."
57
+ MSG_ALREADY="⚠️ ShellWard already installed, updating..."
58
+ MSG_CLONE="Downloading ShellWard..."
59
+ MSG_NPM="Installing via npm..."
60
+ MSG_REGISTER="Registering plugin..."
61
+ MSG_SUCCESS="🎉 Installation successful!"
62
+ MSG_VERIFY="Verifying installation..."
63
+ MSG_USAGE="Usage:"
64
+ MSG_CMD1=" openclaw agent --local -m \"hello\" # Start agent with security"
65
+ MSG_CMD2=" /security # View security status"
66
+ MSG_CMD3=" /audit # View audit log"
67
+ MSG_CMD4=" /harden # Security scan"
68
+ MSG_DOCS="Docs: https://github.com/jnMetaCode/shellward"
69
+ MSG_MODE_TITLE="Choose install method:"
70
+ MSG_MODE_1=" 1) npm install (recommended, auto-update)"
71
+ MSG_MODE_2=" 2) source install (works offline)"
72
+ MSG_MODE_PROMPT="Enter [1/2] (default 1): "
73
+ MSG_DONE="Done! ShellWard will auto-load next time OpenClaw starts."
74
+ MSG_CONFIG="Configuration (optional):"
75
+ fi
76
+
77
+ echo ""
78
+ echo -e "${CYAN}══════════════════════════════════════════${NC}"
79
+ echo -e "${CYAN} $MSG_BANNER${NC}"
80
+ echo -e "${CYAN}══════════════════════════════════════════${NC}"
81
+ echo ""
82
+
83
+ # --- Step 1: Check environment ---
84
+ echo -e "${BLUE}$MSG_CHECKING${NC}"
85
+
86
+ # Check Node.js
87
+ if ! command -v node &>/dev/null; then
88
+ echo -e "${RED}$MSG_NODE_MISSING${NC}"
89
+ exit 1
90
+ fi
91
+
92
+ NODE_VER=$(node -v)
93
+ NODE_MAJOR=$(echo "$NODE_VER" | sed 's/v//' | cut -d. -f1)
94
+ if [ "$NODE_MAJOR" -lt 18 ]; then
95
+ printf "${RED}$MSG_NODE_OLD${NC}\n" "$NODE_VER"
96
+ exit 1
97
+ fi
98
+ printf "${GREEN}$MSG_NODE_OK${NC}\n" "$NODE_VER"
99
+
100
+ # Check OpenClaw
101
+ if ! command -v openclaw &>/dev/null; then
102
+ echo -e "${RED}$MSG_OC_MISSING${NC}"
103
+ exit 1
104
+ fi
105
+
106
+ OC_VER=$(openclaw --version 2>/dev/null | head -1 || echo "unknown")
107
+ printf "${GREEN}$MSG_OC_OK${NC}\n" "$OC_VER"
108
+ echo ""
109
+
110
+ # --- Step 2: Choose install method ---
111
+ INSTALL_METHOD="1"
112
+ if [ -t 0 ]; then
113
+ echo -e "${YELLOW}$MSG_MODE_TITLE${NC}"
114
+ echo -e "$MSG_MODE_1"
115
+ echo -e "$MSG_MODE_2"
116
+ printf "$MSG_MODE_PROMPT"
117
+ read -r choice
118
+ if [ "$choice" = "2" ]; then
119
+ INSTALL_METHOD="2"
120
+ fi
121
+ fi
122
+ echo ""
123
+
124
+ # --- Step 3: Install ---
125
+ PLUGIN_DIR="${HOME}/.openclaw/plugins/shellward"
126
+
127
+ if [ -d "$PLUGIN_DIR" ]; then
128
+ echo -e "${YELLOW}$MSG_ALREADY${NC}"
129
+ rm -rf "$PLUGIN_DIR"
130
+ fi
131
+
132
+ mkdir -p "${HOME}/.openclaw/plugins"
133
+
134
+ clone_install() {
135
+ echo -e "${BLUE}$MSG_CLONE${NC}"
136
+ git clone --depth 1 https://github.com/jnMetaCode/shellward.git "$PLUGIN_DIR" 2>/dev/null
137
+ rm -rf "$PLUGIN_DIR/.git"
138
+ }
139
+
140
+ if [ "$INSTALL_METHOD" = "1" ]; then
141
+ echo -e "${BLUE}$MSG_NPM${NC}"
142
+ cd /tmp
143
+ rm -rf shellward-npm-install
144
+ mkdir shellward-npm-install && cd shellward-npm-install
145
+ if npm pack shellward 2>/dev/null; then
146
+ tar xzf shellward-*.tgz
147
+ mv package "$PLUGIN_DIR"
148
+ # Verify npm package has correct structure
149
+ if [ ! -f "$PLUGIN_DIR/src/index.ts" ]; then
150
+ echo -e "${YELLOW}npm package outdated, switching to git...${NC}"
151
+ rm -rf "$PLUGIN_DIR"
152
+ clone_install
153
+ fi
154
+ else
155
+ clone_install
156
+ fi
157
+ cd /tmp && rm -rf shellward-npm-install
158
+ else
159
+ clone_install
160
+ fi
161
+
162
+ # Fix ownership
163
+ if [ "$(id -u)" = "0" ]; then
164
+ chown -R root:root "$PLUGIN_DIR"
165
+ fi
166
+
167
+ echo ""
168
+
169
+ # --- Step 4: Verify ---
170
+ echo -e "${BLUE}$MSG_VERIFY${NC}"
171
+ if [ -f "$PLUGIN_DIR/src/index.ts" ] && [ -f "$PLUGIN_DIR/openclaw.plugin.json" ]; then
172
+ echo -e "${GREEN}$MSG_SUCCESS${NC}"
173
+ else
174
+ echo -e "${RED}Installation failed — files missing${NC}"
175
+ exit 1
176
+ fi
177
+
178
+ echo ""
179
+ echo -e "${CYAN}══════════════════════════════════════════${NC}"
180
+ echo -e "${GREEN}$MSG_DONE${NC}"
181
+ echo ""
182
+ echo -e "${YELLOW}$MSG_USAGE${NC}"
183
+ echo -e "$MSG_CMD1"
184
+ echo -e "$MSG_CMD2"
185
+ echo -e "$MSG_CMD3"
186
+ echo -e "$MSG_CMD4"
187
+ echo ""
188
+ echo -e "${YELLOW}$MSG_CONFIG${NC}"
189
+ cat <<'CONF'
190
+ # ~/.openclaw/openclaw.json → plugins section:
191
+ {
192
+ "plugins": {
193
+ "entries": {
194
+ "shellward": { "enabled": true }
195
+ }
196
+ }
197
+ }
198
+ CONF
199
+ echo ""
200
+ echo -e "${BLUE}$MSG_DOCS${NC}"
201
+ echo ""
@@ -0,0 +1,47 @@
1
+ {
2
+ "id": "shellward",
3
+ "name": "ShellWard",
4
+ "description": "First bilingual (EN/ZH) security plugin for OpenClaw — injection detection, dangerous operation blocking, PII/secret redaction (incl. Chinese ID card, phone, bank card), audit logging",
5
+ "version": "0.3.2",
6
+ "skills": ["./skills"],
7
+ "configSchema": {
8
+ "type": "object",
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "mode": {
12
+ "type": "string",
13
+ "enum": ["enforce", "audit"],
14
+ "default": "enforce",
15
+ "description": "enforce = block + log, audit = log only"
16
+ },
17
+ "locale": {
18
+ "type": "string",
19
+ "enum": ["auto", "zh", "en"],
20
+ "default": "auto",
21
+ "description": "auto = detect from system language"
22
+ },
23
+ "layers": {
24
+ "type": "object",
25
+ "properties": {
26
+ "promptGuard": { "type": "boolean", "default": true },
27
+ "outputScanner": { "type": "boolean", "default": true },
28
+ "toolBlocker": { "type": "boolean", "default": true },
29
+ "inputAuditor": { "type": "boolean", "default": true },
30
+ "securityGate": { "type": "boolean", "default": true },
31
+ "outboundGuard": { "type": "boolean", "default": true },
32
+ "dataFlowGuard": { "type": "boolean", "default": true },
33
+ "sessionGuard": { "type": "boolean", "default": true }
34
+ }
35
+ },
36
+ "injectionThreshold": {
37
+ "type": "number",
38
+ "default": 60,
39
+ "description": "Injection risk score threshold (0-100) to trigger block/alert"
40
+ }
41
+ }
42
+ },
43
+ "uiHints": {
44
+ "mode": { "label": "Security Mode", "help": "enforce blocks dangerous operations; audit only logs them" },
45
+ "locale": { "label": "Language", "help": "auto detects from system LANG; zh for Chinese; en for English" }
46
+ }
47
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "shellward",
3
+ "version": "0.3.2",
4
+ "description": "First bilingual (EN/ZH) security plugin for OpenClaw — injection detection, dangerous operation blocking, PII/secret redaction, audit logging",
5
+ "keywords": [
6
+ "openclaw",
7
+ "security",
8
+ "plugin",
9
+ "injection-detection",
10
+ "pii-redaction",
11
+ "chinese",
12
+ "bilingual"
13
+ ],
14
+ "author": "jnMetaCode",
15
+ "license": "Apache-2.0",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/jnMetaCode/clawguard"
19
+ },
20
+ "type": "module",
21
+ "main": "src/index.ts",
22
+ "openclaw": {
23
+ "extensions": [
24
+ "./src/index.ts"
25
+ ]
26
+ },
27
+ "files": [
28
+ "src/",
29
+ "skills/",
30
+ "openclaw.plugin.json",
31
+ "install.sh",
32
+ "install.ps1",
33
+ "LICENSE",
34
+ "README.md"
35
+ ],
36
+ "engines": {
37
+ "node": ">=18"
38
+ }
39
+ }
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: security-guide
3
+ description: OpenClaw 安全部署指南 / Security deployment guide — help users secure their OpenClaw installation
4
+ user-invocable: true
5
+ disable-model-invocation: false
6
+ ---
7
+
8
+ # ShellWard Security Deployment Guide / 安全部署指南
9
+
10
+ When the user invokes this skill, provide a complete security deployment checklist based on the following best practices. Check the current system state using available tools and give actionable recommendations.
11
+
12
+ ## Security Checklist
13
+
14
+ ### 1. Network Control / 网络控制
15
+ - Check if OpenClaw gateway port (19000/19001) is exposed to public network
16
+ - Recommend binding to 127.0.0.1 or using a reverse proxy with authentication
17
+ - Suggest firewall rules: `ufw allow from 127.0.0.1 to any port 19000`
18
+ - For cloud servers: check security group rules
19
+
20
+ ### 2. Container Isolation / 容器隔离
21
+ - Recommend running OpenClaw in Docker with restricted capabilities:
22
+ ```
23
+ docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE \
24
+ --read-only --tmpfs /tmp \
25
+ -u 1000:1000 \
26
+ openclaw
27
+ ```
28
+ - Suggest resource limits: `--memory=2g --cpus=1`
29
+ - Mount only necessary directories
30
+
31
+ ### 3. Credential Management / 凭证管理
32
+ - Scan for plaintext secrets in .env, .bashrc, environment variables
33
+ - Recommend using a secret manager (Vault, doppler, etc.)
34
+ - Check file permissions on sensitive files (should be 0600)
35
+ - Suggest `chmod 600 ~/.env ~/.ssh/* ~/.aws/credentials`
36
+
37
+ ### 4. Audit Logging / 审计日志
38
+ - Verify ShellWard audit log is active at ~/.openclaw/shellward/audit.jsonl
39
+ - Show recent security events
40
+ - Recommend log rotation and backup strategy
41
+ - Suggest sending critical events to external SIEM
42
+
43
+ ### 5. Plugin Security / 插件安全
44
+ - List all installed plugins and check for known risks
45
+ - Disable auto-update for plugins
46
+ - Only install from trusted sources
47
+ - Scan plugin code for suspicious patterns
48
+
49
+ ### 6. Patch Management / 补丁管理
50
+ - Check current OpenClaw version
51
+ - Report known vulnerabilities for current version
52
+ - Recommend upgrade path
53
+ - Check Node.js version (must be >= 22.12)
54
+
55
+ ## Available Commands
56
+ Remind the user about ShellWard's quick commands:
57
+ - `/security` — Full security status overview
58
+ - `/audit [count] [filter]` — View audit log
59
+ - `/harden` — Scan for issues, `/harden fix` to auto-fix
60
+ - `/scan-plugins` — Scan plugins for security risks
61
+ - `/check-updates` — Check versions and vulnerabilities
62
+
63
+ ## Response Style
64
+ - Be concise and actionable
65
+ - Use the user's language (detect from their message)
66
+ - Prioritize critical issues first
67
+ - For each issue, provide the exact command to fix it
68
+ - Ask for confirmation before executing destructive operations
@@ -0,0 +1,57 @@
1
+ // src/audit-log.ts — JSONL audit log, zero dependencies
2
+
3
+ import { appendFileSync, chmodSync, mkdirSync, renameSync, statSync, writeFileSync } from 'fs'
4
+ import { join } from 'path'
5
+ import type { AuditEntry, ShellWardConfig } from './types'
6
+
7
+ const LOG_DIR = join(process.env.HOME || '~', '.openclaw', 'shellward')
8
+ const LOG_FILE = join(LOG_DIR, 'audit.jsonl')
9
+ const MAX_SIZE_BYTES = 100 * 1024 * 1024 // 100 MB
10
+
11
+ export class AuditLog {
12
+ private config: ShellWardConfig
13
+ private rotating = false
14
+
15
+ constructor(config: ShellWardConfig) {
16
+ this.config = config
17
+ try {
18
+ mkdirSync(LOG_DIR, { recursive: true, mode: 0o700 })
19
+ // Ensure log file exists with restricted permissions (owner-only)
20
+ try {
21
+ statSync(LOG_FILE)
22
+ } catch {
23
+ writeFileSync(LOG_FILE, '', { mode: 0o600 })
24
+ }
25
+ } catch { /* directory may already exist */ }
26
+ }
27
+
28
+ write(entry: Omit<AuditEntry, 'ts' | 'mode'>): void {
29
+ try {
30
+ const record: AuditEntry = {
31
+ ts: new Date().toISOString(),
32
+ mode: this.config.mode,
33
+ ...entry,
34
+ }
35
+ appendFileSync(LOG_FILE, JSON.stringify(record) + '\n', { mode: 0o600 })
36
+ this.rotateIfNeeded()
37
+ } catch (e: any) {
38
+ // Log failure must not break plugin, but warn via stderr
39
+ try { process.stderr.write(`[ShellWard] audit log write failed: ${e?.message}\n`) } catch {}
40
+ }
41
+ }
42
+
43
+ private rotateIfNeeded(): void {
44
+ if (this.rotating) return
45
+ try {
46
+ const stat = statSync(LOG_FILE)
47
+ if (stat.size > MAX_SIZE_BYTES) {
48
+ this.rotating = true
49
+ const ts = new Date().toISOString().replace(/[:.]/g, '-')
50
+ renameSync(LOG_FILE, `${LOG_FILE}.${ts}.bak`)
51
+ writeFileSync(LOG_FILE, '', { mode: 0o600 })
52
+ }
53
+ } catch { /* ignore */ } finally {
54
+ this.rotating = false
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,79 @@
1
+ // src/commands/audit.ts — /audit command: view recent audit log entries
2
+
3
+ import { readFileSync, statSync } from 'fs'
4
+ import { join } from 'path'
5
+ import type { ShellWardConfig } from '../types'
6
+ import { resolveLocale } from '../types'
7
+
8
+ const LOG_FILE = join(process.env.HOME || '~', '.openclaw', 'shellward', 'audit.jsonl')
9
+
10
+ export function registerAuditCommand(api: any, config: ShellWardConfig) {
11
+ const locale = resolveLocale(config)
12
+
13
+ api.registerCommand({
14
+ name: 'audit',
15
+ description: locale === 'zh'
16
+ ? '📋 查看 ShellWard 审计日志 (用法: /audit [数量] [block|redact|critical])'
17
+ : '📋 View ShellWard audit log (usage: /audit [count] [block|redact|critical])',
18
+ acceptsArgs: true,
19
+ handler: (ctx: any) => {
20
+ const zh = locale === 'zh'
21
+ const args = (ctx.args || '').trim().split(/\s+/).filter(Boolean)
22
+
23
+ // Parse args: count and optional filter
24
+ let count = 20
25
+ let filter = ''
26
+ for (const arg of args) {
27
+ if (/^\d+$/.test(arg)) {
28
+ count = Math.min(parseInt(arg), 100)
29
+ } else {
30
+ filter = arg.toLowerCase()
31
+ }
32
+ }
33
+
34
+ try {
35
+ statSync(LOG_FILE)
36
+ } catch {
37
+ return { text: zh ? '⚠️ 审计日志文件不存在,尚无安全事件记录。' : '⚠️ Audit log not found. No security events recorded yet.' }
38
+ }
39
+
40
+ const content = readFileSync(LOG_FILE, 'utf-8')
41
+ let lines = content.trim().split('\n').filter(Boolean)
42
+
43
+ // Apply filter
44
+ if (filter === 'block') {
45
+ lines = lines.filter(l => l.includes('"action":"block"'))
46
+ } else if (filter === 'redact') {
47
+ lines = lines.filter(l => l.includes('"action":"redact"'))
48
+ } else if (filter === 'critical') {
49
+ lines = lines.filter(l => l.includes('"level":"CRITICAL"'))
50
+ } else if (filter === 'high') {
51
+ lines = lines.filter(l => l.includes('"level":"HIGH"') || l.includes('"level":"CRITICAL"'))
52
+ }
53
+
54
+ // Get last N entries
55
+ const recent = lines.slice(-count)
56
+
57
+ if (recent.length === 0) {
58
+ return { text: zh ? '✅ 没有匹配的审计事件。' : '✅ No matching audit events.' }
59
+ }
60
+
61
+ const header = zh
62
+ ? `📋 **审计日志** (最近 ${recent.length} 条${filter ? `, 过滤: ${filter}` : ''})`
63
+ : `📋 **Audit Log** (last ${recent.length} entries${filter ? `, filter: ${filter}` : ''})`
64
+
65
+ const formatted = recent.map(line => {
66
+ try {
67
+ const e = JSON.parse(line)
68
+ const icon = e.action === 'block' ? '🚫' : e.action === 'redact' ? '🔒' : e.level === 'CRITICAL' ? '🔴' : 'ℹ️'
69
+ const time = e.ts?.slice(11, 19) || '??:??:??'
70
+ return `${icon} \`${time}\` **${e.layer}** ${e.action}: ${e.detail?.slice(0, 80) || ''}${e.pattern ? ` [${e.pattern}]` : ''}`
71
+ } catch {
72
+ return line.slice(0, 100)
73
+ }
74
+ })
75
+
76
+ return { text: `${header}\n\n${formatted.join('\n')}` }
77
+ },
78
+ })
79
+ }
@@ -0,0 +1,151 @@
1
+ // src/commands/check-updates.ts — /check-updates: check OpenClaw version and known vulnerabilities
2
+
3
+ import { execSync } from 'child_process'
4
+ import { existsSync, readFileSync } from 'fs'
5
+ import { join } from 'path'
6
+ import type { ShellWardConfig } from '../types'
7
+ import { resolveLocale } from '../types'
8
+
9
+ // Known vulnerability database (hardcoded, updated with plugin releases)
10
+ // Format: { version_range, severity, cve, description_zh, description_en }
11
+ const KNOWN_VULNS = [
12
+ {
13
+ affectedBelow: '2026.3.6',
14
+ severity: 'HIGH',
15
+ id: 'CG-2026-001',
16
+ description_zh: 'tool_result_persist hook 可被绕过泄露敏感数据',
17
+ description_en: 'tool_result_persist hook bypass may leak sensitive data',
18
+ },
19
+ {
20
+ affectedBelow: '2026.3.4',
21
+ severity: 'CRITICAL',
22
+ id: 'CG-2026-002',
23
+ description_zh: '插件系统缺少签名验证,可加载恶意插件',
24
+ description_en: 'Plugin system lacks signature verification, allows malicious plugins',
25
+ },
26
+ {
27
+ affectedBelow: '2026.3.2',
28
+ severity: 'HIGH',
29
+ id: 'CG-2026-003',
30
+ description_zh: 'Gateway 默认绑定 0.0.0.0,未认证即可远程执行',
31
+ description_en: 'Gateway binds 0.0.0.0 by default, allows unauthenticated remote execution',
32
+ },
33
+ ]
34
+
35
+ export function registerCheckUpdatesCommand(api: any, config: ShellWardConfig) {
36
+ const locale = resolveLocale(config)
37
+
38
+ api.registerCommand({
39
+ name: 'check-updates',
40
+ description: locale === 'zh'
41
+ ? '🔄 检查 OpenClaw 版本和已知漏洞'
42
+ : '🔄 Check OpenClaw version and known vulnerabilities',
43
+ acceptsArgs: false,
44
+ handler: () => {
45
+ const zh = locale === 'zh'
46
+ const lines: string[] = []
47
+
48
+ lines.push(zh ? '🔄 **版本与漏洞检查**' : '🔄 **Version & Vulnerability Check**')
49
+ lines.push('')
50
+
51
+ // 1. Get OpenClaw version
52
+ let currentVersion = 'unknown'
53
+ try {
54
+ const out = execSync('openclaw --version 2>&1', { timeout: 5000 }).toString().trim()
55
+ // Extract version like "2026.3.8"
56
+ const match = out.match(/(\d{4}\.\d+\.\d+)/)
57
+ if (match) currentVersion = match[1]
58
+ } catch { /* skip */ }
59
+
60
+ lines.push(zh
61
+ ? `### OpenClaw 版本: ${currentVersion}`
62
+ : `### OpenClaw Version: ${currentVersion}`)
63
+ lines.push('')
64
+
65
+ // 2. Check ShellWard version
66
+ let shellwardVersion = 'unknown'
67
+ try {
68
+ const pkgPath = join(__dirname, '../../package.json')
69
+ if (existsSync(pkgPath)) {
70
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
71
+ shellwardVersion = pkg.version || 'unknown'
72
+ }
73
+ } catch { /* skip */ }
74
+
75
+ lines.push(zh
76
+ ? `### ShellWard 版本: ${shellwardVersion}`
77
+ : `### ShellWard Version: ${shellwardVersion}`)
78
+ lines.push('')
79
+
80
+ // 3. Check known vulnerabilities
81
+ lines.push(zh ? '### 已知漏洞检查' : '### Known Vulnerability Check')
82
+
83
+ if (currentVersion === 'unknown') {
84
+ lines.push(zh
85
+ ? ' ⚠️ 无法确定 OpenClaw 版本,请手动检查'
86
+ : ' ⚠️ Cannot determine OpenClaw version, please check manually')
87
+ } else {
88
+ const affected = KNOWN_VULNS.filter(v => compareVersions(currentVersion, v.affectedBelow) < 0)
89
+ if (affected.length === 0) {
90
+ lines.push(zh
91
+ ? ' ✅ 当前版本未发现已知漏洞'
92
+ : ' ✅ No known vulnerabilities for current version')
93
+ } else {
94
+ for (const vuln of affected) {
95
+ const icon = vuln.severity === 'CRITICAL' ? '🔴' : '🟡'
96
+ const desc = zh ? vuln.description_zh : vuln.description_en
97
+ lines.push(` ${icon} **${vuln.id}** [${vuln.severity}]: ${desc}`)
98
+ lines.push(zh
99
+ ? ` 影响版本: < ${vuln.affectedBelow} — 请升级 OpenClaw`
100
+ : ` Affected: < ${vuln.affectedBelow} — please upgrade OpenClaw`)
101
+ }
102
+ }
103
+ }
104
+ lines.push('')
105
+
106
+ // 4. Check Node.js version
107
+ lines.push(zh ? '### 运行环境' : '### Runtime Environment')
108
+ try {
109
+ const nodeVer = process.version
110
+ const major = parseInt(nodeVer.slice(1))
111
+ if (major < 22) {
112
+ lines.push(zh
113
+ ? ` ⚠️ Node.js ${nodeVer} — OpenClaw 要求 >= 22.12,请升级`
114
+ : ` ⚠️ Node.js ${nodeVer} — OpenClaw requires >= 22.12, please upgrade`)
115
+ } else {
116
+ lines.push(zh
117
+ ? ` ✅ Node.js ${nodeVer}`
118
+ : ` ✅ Node.js ${nodeVer}`)
119
+ }
120
+ } catch { /* skip */ }
121
+
122
+ lines.push(` ${zh ? '平台' : 'Platform'}: ${process.platform} ${process.arch}`)
123
+ lines.push('')
124
+
125
+ // 5. Recommendations
126
+ lines.push('---')
127
+ lines.push(zh
128
+ ? '💡 **建议**: 定期运行 `/check-updates` 检查,及时升级到最新版本'
129
+ : '💡 **Tip**: Run `/check-updates` regularly, upgrade to latest versions promptly')
130
+ lines.push(zh
131
+ ? '📖 关注 OpenClaw 安全公告: https://github.com/nicepkg/openclaw/security'
132
+ : '📖 Follow OpenClaw security advisories: https://github.com/nicepkg/openclaw/security')
133
+
134
+ return { text: lines.join('\n') }
135
+ },
136
+ })
137
+ }
138
+
139
+ /**
140
+ * Compare two version strings like "2026.3.8" vs "2026.3.6"
141
+ * Returns: negative if a < b, 0 if equal, positive if a > b
142
+ */
143
+ function compareVersions(a: string, b: string): number {
144
+ const pa = a.split('.').map(Number)
145
+ const pb = b.split('.').map(Number)
146
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
147
+ const diff = (pa[i] || 0) - (pb[i] || 0)
148
+ if (diff !== 0) return diff
149
+ }
150
+ return 0
151
+ }