1- // src/commands/check-updates.ts — /check-updates: check OpenClaw version and known vulnerabilities
1+ // src/commands/check-updates.ts — /check-updates: check versions + remote vulnerability DB
22
33import { execSync } from 'child_process'
44import { existsSync , readFileSync } from 'fs'
55import { join } from 'path'
66import type { ShellWardConfig } from '../types'
77import { resolveLocale } from '../types'
8+ import { checkForUpdate , fetchVulnDB , compareVersions } from '../update-check'
89
9- // Known vulnerability database (hardcoded, updated with plugin releases )
10- // Format: { version_range, severity, cve, description_zh, description_en }
11- const KNOWN_VULNS = [
10+ // Local fallback vulnerability database (used when remote fetch fails )
11+ // Contains only CVE-assigned vulnerabilities as minimum baseline
12+ const LOCAL_VULNS = [
1213 {
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 ' ,
14+ affectedBelow : '1.0.111 ' ,
15+ severity : 'HIGH' as const ,
16+ id : 'CVE-2025-59536 ' ,
17+ description_zh : '远程代码执行:恶意仓库通过 Hooks 和 MCP Server 在信任提示前执行任意命令 (CVSS 8.7) ' ,
18+ description_en : 'RCE via Hooks and MCP Server bypass — arbitrary shell execution before trust dialog (CVSS 8.7) ' ,
1819 } ,
1920 {
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 ' ,
21+ affectedBelow : '2.0.65 ' ,
22+ severity : 'MEDIUM' as const ,
23+ id : 'CVE -2026-21852 ' ,
24+ description_zh : 'API 密钥泄露:恶意仓库通过 settings.json 设置 ANTHROPIC_BASE_URL 窃取用户 API Key (CVSS 5.3) ' ,
25+ description_en : 'API key exfiltration via ANTHROPIC_BASE_URL in settings.json before trust prompt (CVSS 5.3) ' ,
2526 } ,
2627 {
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 ' ,
28+ affectedBelow : '2026.2.7 ' ,
29+ severity : 'HIGH' as const ,
30+ id : 'GHSA-ff64-7w26-62rf ' ,
31+ description_zh : '沙箱逃逸:通过 settings.json 持久化配置注入 ' ,
32+ description_en : 'Sandbox escape via persistent configuration injection in settings.json ' ,
3233 } ,
3334]
3435
@@ -38,31 +39,30 @@ export function registerCheckUpdatesCommand(api: any, config: ShellWardConfig) {
3839 api . registerCommand ( {
3940 name : 'check-updates' ,
4041 description : locale === 'zh'
41- ? '🔄 检查 OpenClaw 版本和已知漏洞 '
42- : '🔄 Check OpenClaw version and known vulnerabilities' ,
42+ ? '🔄 检查版本更新和已知漏洞(支持远程漏洞库) '
43+ : '🔄 Check for updates and known vulnerabilities (remote vuln DB) ' ,
4344 acceptsArgs : false ,
44- handler : ( ) => {
45+ handler : async ( ) => {
4546 const zh = locale === 'zh'
4647 const lines : string [ ] = [ ]
4748
4849 lines . push ( zh ? '🔄 **版本与漏洞检查**' : '🔄 **Version & Vulnerability Check**' )
4950 lines . push ( '' )
5051
5152 // 1. Get OpenClaw version
52- let currentVersion = 'unknown'
53+ let openclawVersion = 'unknown'
5354 try {
5455 const out = execSync ( 'openclaw --version 2>&1' , { timeout : 5000 } ) . toString ( ) . trim ( )
55- // Extract version like "2026.3.8"
5656 const match = out . match ( / ( \d { 4 } \. \d + \. \d + ) / )
57- if ( match ) currentVersion = match [ 1 ]
57+ if ( match ) openclawVersion = match [ 1 ]
5858 } catch { /* skip */ }
5959
6060 lines . push ( zh
61- ? `### OpenClaw 版本: ${ currentVersion } `
62- : `### OpenClaw Version: ${ currentVersion } ` )
61+ ? `### OpenClaw 版本: ${ openclawVersion } `
62+ : `### OpenClaw Version: ${ openclawVersion } ` )
6363 lines . push ( '' )
6464
65- // 2. Check ShellWard version
65+ // 2. Check ShellWard version + available update
6666 let shellwardVersion = 'unknown'
6767 try {
6868 const pkgPath = join ( __dirname , '../../package.json' )
@@ -75,17 +75,45 @@ export function registerCheckUpdatesCommand(api: any, config: ShellWardConfig) {
7575 lines . push ( zh
7676 ? `### ShellWard 版本: ${ shellwardVersion } `
7777 : `### ShellWard Version: ${ shellwardVersion } ` )
78+
79+ // Check for ShellWard update from npm
80+ try {
81+ const updateInfo = await checkForUpdate ( shellwardVersion )
82+ if ( updateInfo ?. updateAvailable ) {
83+ lines . push ( zh
84+ ? ` 🆕 **新版本 v${ updateInfo . latest } 可用!** 运行 \`openclaw plugins update shellward\` 更新`
85+ : ` 🆕 **v${ updateInfo . latest } available!** Run \`openclaw plugins update shellward\` to update` )
86+ } else if ( updateInfo ) {
87+ lines . push ( zh ? ' ✅ 已是最新版本' : ' ✅ Up to date' )
88+ }
89+ } catch { /* skip */ }
7890 lines . push ( '' )
7991
80- // 3. Check known vulnerabilities
92+ // 3. Check known vulnerabilities (remote DB with local fallback)
8193 lines . push ( zh ? '### 已知漏洞检查' : '### Known Vulnerability Check' )
8294
83- if ( currentVersion === 'unknown' ) {
95+ let vulnDB = LOCAL_VULNS
96+ let alerts : { id : string ; severity : string ; date : string ; description_zh : string ; description_en : string } [ ] = [ ]
97+ let dbSource = 'local'
98+ try {
99+ const remote = await fetchVulnDB ( )
100+ if ( remote . vulns . length > 0 ) {
101+ vulnDB = remote . vulns
102+ dbSource = 'remote'
103+ }
104+ alerts = remote . alerts || [ ]
105+ } catch { /* use local */ }
106+
107+ lines . push ( zh
108+ ? ` 数据源: ${ dbSource === 'remote' ? `远程漏洞库 (GitHub) — ${ vulnDB . length } 条记录` : '本地内置数据库' } `
109+ : ` Source: ${ dbSource === 'remote' ? `Remote vuln DB (GitHub) — ${ vulnDB . length } entries` : 'Local built-in database' } ` )
110+
111+ if ( openclawVersion === 'unknown' ) {
84112 lines . push ( zh
85113 ? ' ⚠️ 无法确定 OpenClaw 版本,请手动检查'
86114 : ' ⚠️ Cannot determine OpenClaw version, please check manually' )
87115 } else {
88- const affected = KNOWN_VULNS . filter ( v => compareVersions ( currentVersion , v . affectedBelow ) < 0 )
116+ const affected = vulnDB . filter ( v => compareVersions ( openclawVersion , v . affectedBelow ) < 0 )
89117 if ( affected . length === 0 ) {
90118 lines . push ( zh
91119 ? ' ✅ 当前版本未发现已知漏洞'
@@ -96,11 +124,22 @@ export function registerCheckUpdatesCommand(api: any, config: ShellWardConfig) {
96124 const desc = zh ? vuln . description_zh : vuln . description_en
97125 lines . push ( ` ${ icon } **${ vuln . id } ** [${ vuln . severity } ]: ${ desc } ` )
98126 lines . push ( zh
99- ? ` 影响版本: < ${ vuln . affectedBelow } — 请升级 OpenClaw `
100- : ` Affected: < ${ vuln . affectedBelow } — please upgrade OpenClaw ` )
127+ ? ` 影响版本: < ${ vuln . affectedBelow } — 请升级`
128+ : ` Affected: < ${ vuln . affectedBelow } — please upgrade` )
101129 }
102130 }
103131 }
132+
133+ // Supply chain alerts
134+ if ( alerts . length > 0 ) {
135+ lines . push ( '' )
136+ lines . push ( zh ? '### 供应链安全警告' : '### Supply Chain Alerts' )
137+ for ( const alert of alerts ) {
138+ const icon = alert . severity === 'CRITICAL' ? '🔴' : '🟡'
139+ const desc = zh ? alert . description_zh : alert . description_en
140+ lines . push ( ` ${ icon } **${ alert . id } ** [${ alert . date } ]: ${ desc } ` )
141+ }
142+ }
104143 lines . push ( '' )
105144
106145 // 4. Check Node.js version
@@ -135,17 +174,3 @@ export function registerCheckUpdatesCommand(api: any, config: ShellWardConfig) {
135174 } ,
136175 } )
137176}
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- }
0 commit comments