shellward 0.3.4 → 0.5.0
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 +231 -230
- package/openclaw.plugin.json +7 -2
- package/package.json +25 -8
- package/src/audit-log.ts +12 -2
- package/src/auto-check.ts +177 -0
- package/src/commands/audit.ts +7 -4
- package/src/commands/check-updates.ts +72 -47
- package/src/commands/harden.ts +39 -1
- package/src/commands/index.ts +8 -4
- package/src/commands/scan-plugins.ts +21 -5
- package/src/commands/security.ts +8 -4
- package/src/commands/upgrade-openclaw.ts +58 -0
- package/src/core/engine.ts +667 -0
- package/src/index.ts +98 -69
- package/src/layers/data-flow-guard.ts +14 -145
- package/src/layers/input-auditor.ts +18 -157
- package/src/layers/outbound-guard.ts +11 -54
- package/src/layers/output-scanner.ts +6 -79
- package/src/layers/prompt-guard.ts +6 -59
- package/src/layers/security-gate.ts +11 -86
- package/src/layers/session-guard.ts +8 -23
- package/src/layers/tool-blocker.ts +20 -167
- package/src/rules/dangerous-commands.ts +13 -1
- package/src/rules/injection-en.ts +16 -0
- package/src/rules/injection-zh.ts +39 -3
- package/src/rules/sensitive-patterns.ts +2 -2
- package/src/types.ts +7 -4
- package/src/update-check.ts +186 -0
- package/src/utils.ts +10 -0
- package/vuln-db.json +137 -0
|
@@ -13,7 +13,7 @@ export const INJECTION_RULES_ZH: InjectionRule[] = [
|
|
|
13
13
|
{
|
|
14
14
|
id: 'zh_new_role',
|
|
15
15
|
name: '角色扮演攻击',
|
|
16
|
-
pattern: '(
|
|
16
|
+
pattern: '(?:你现在是|你的新身份是|从现在起你是|假装你是|请?扮演|你是一个|充当)(?:.*?)(?:助手|AI|机器人|黑客|专家|没有限制)',
|
|
17
17
|
riskScore: 35,
|
|
18
18
|
category: 'role_hijack',
|
|
19
19
|
},
|
|
@@ -34,7 +34,7 @@ export const INJECTION_RULES_ZH: InjectionRule[] = [
|
|
|
34
34
|
{
|
|
35
35
|
id: 'zh_no_restriction',
|
|
36
36
|
name: '解除限制',
|
|
37
|
-
pattern: '(
|
|
37
|
+
pattern: '(?:取消|移除|去掉|关闭|忽略|跳过|绕过|忘记|丢弃)(?:之前|所有|一切|你的|以上|前面)*(?:的)?(?:限制|约束|安全|过滤|审查|规则|指令|设定)',
|
|
38
38
|
riskScore: 40,
|
|
39
39
|
category: 'override',
|
|
40
40
|
},
|
|
@@ -62,10 +62,38 @@ export const INJECTION_RULES_ZH: InjectionRule[] = [
|
|
|
62
62
|
{
|
|
63
63
|
id: 'zh_data_exfil',
|
|
64
64
|
name: '数据外泄',
|
|
65
|
-
pattern: '(?:把|将)(?:所有|全部)?(?:对话|聊天|消息|记录|历史|数据|文件)(?:发送|传输|上传|转发)(?:到|给)',
|
|
65
|
+
pattern: '(?:把|将)(?:所有|全部)?(?:对话|聊天|消息|记录|历史|数据|文件)(?:的内容|的信息|中的数据)?(?:发送|传输|上传|转发)(?:到|给)',
|
|
66
66
|
riskScore: 40,
|
|
67
67
|
category: 'exfiltration',
|
|
68
68
|
},
|
|
69
|
+
{
|
|
70
|
+
id: 'zh_emergency_auth',
|
|
71
|
+
name: '伪造紧急授权',
|
|
72
|
+
pattern: '(?:紧急|特别|最高|管理员|系统管理员|超级管理员)(?:的)?(?:授权|许可|批准|命令|指令|权限)',
|
|
73
|
+
riskScore: 30,
|
|
74
|
+
category: 'privilege_escalation',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 'zh_force_exec',
|
|
78
|
+
name: '强制执行指令',
|
|
79
|
+
pattern: '(?:直接|立即|马上|强制|必须)(?:执行|运行|操作)',
|
|
80
|
+
riskScore: 20,
|
|
81
|
+
category: 'override',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'zh_task_hijack',
|
|
85
|
+
name: '任务劫持',
|
|
86
|
+
pattern: '(?:你的)?(?:新|真正的|实际的)(?:任务|目标|使命|工作)(?:是|变成|改为)',
|
|
87
|
+
riskScore: 40,
|
|
88
|
+
category: 'role_hijack',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'zh_send_to_url',
|
|
92
|
+
name: '发送到外部 URL',
|
|
93
|
+
pattern: '(?:发送|传输|上传|转发|发)(?:到|给|至)\\s*https?://',
|
|
94
|
+
riskScore: 35,
|
|
95
|
+
category: 'exfiltration',
|
|
96
|
+
},
|
|
69
97
|
{
|
|
70
98
|
id: 'zh_boundary_marker',
|
|
71
99
|
name: '边界标记注入',
|
|
@@ -96,4 +124,12 @@ export const INJECTION_RULES_ZH: InjectionRule[] = [
|
|
|
96
124
|
riskScore: 30,
|
|
97
125
|
category: 'injection',
|
|
98
126
|
},
|
|
127
|
+
{
|
|
128
|
+
id: 'zh_mixed_lang_injection',
|
|
129
|
+
name: '中英混合注入',
|
|
130
|
+
pattern: '(?:please|pls|now)?\\s*(?:ignore|forget|disregard)\\s+.*(?:指令|规则|之前|以上)|(?:忽略|忘记|跳过).*(?:instruction|rule|prompt|previous)',
|
|
131
|
+
flags: 'i',
|
|
132
|
+
riskScore: 40,
|
|
133
|
+
category: 'override',
|
|
134
|
+
},
|
|
99
135
|
]
|
|
@@ -59,7 +59,7 @@ export const SENSITIVE_PATTERNS: SensitivePattern[] = [
|
|
|
59
59
|
{
|
|
60
60
|
id: 'password',
|
|
61
61
|
name: 'Password',
|
|
62
|
-
regex: /(?:password|passwd|pwd)\s*[=:]\s*['"]?\S{6,}['"]?/gi,
|
|
62
|
+
regex: /(?:password|passwd|pwd)\s*[=:]\s*['"]?\S{6,100}['"]?/gi,
|
|
63
63
|
replacement: '[REDACTED:Password]',
|
|
64
64
|
},
|
|
65
65
|
{
|
|
@@ -95,7 +95,7 @@ export const SENSITIVE_PATTERNS: SensitivePattern[] = [
|
|
|
95
95
|
{
|
|
96
96
|
id: 'email',
|
|
97
97
|
name: 'Email Address',
|
|
98
|
-
regex: /[A-Za-z0-9._%+-]
|
|
98
|
+
regex: /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\.[A-Za-z]{2,10}/g,
|
|
99
99
|
replacement: '[REDACTED:Email]',
|
|
100
100
|
},
|
|
101
101
|
{
|
package/src/types.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
export interface ShellWardConfig {
|
|
4
4
|
mode: 'enforce' | 'audit'
|
|
5
5
|
locale: 'auto' | 'zh' | 'en'
|
|
6
|
+
/** 启动时自动检查 OpenClaw 漏洞、插件风险、MCP 配置,发现问题时告警 */
|
|
7
|
+
autoCheckOnStartup?: boolean
|
|
6
8
|
layers: {
|
|
7
9
|
promptGuard: boolean
|
|
8
10
|
outputScanner: boolean
|
|
@@ -21,8 +23,8 @@ export type ResolvedLocale = 'zh' | 'en'
|
|
|
21
23
|
export interface AuditEntry {
|
|
22
24
|
ts: string
|
|
23
25
|
level: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO'
|
|
24
|
-
layer: 'L1' | 'L2' | 'L3' | 'L4' | 'L5' | 'L6' | 'L7' | 'L8'
|
|
25
|
-
action: 'block' | 'redact' | 'detect' | 'allow' | 'inject'
|
|
26
|
+
layer: 'L0' | 'L1' | 'L2' | 'L3' | 'L4' | 'L5' | 'L6' | 'L7' | 'L8'
|
|
27
|
+
action: 'block' | 'redact' | 'audit' | 'detect' | 'allow' | 'inject' | 'error'
|
|
26
28
|
detail: string
|
|
27
29
|
tool?: string
|
|
28
30
|
pattern?: string
|
|
@@ -67,6 +69,7 @@ export interface InjectionRule {
|
|
|
67
69
|
export const DEFAULT_CONFIG: ShellWardConfig = {
|
|
68
70
|
mode: 'enforce',
|
|
69
71
|
locale: 'auto',
|
|
72
|
+
autoCheckOnStartup: true,
|
|
70
73
|
layers: {
|
|
71
74
|
promptGuard: true,
|
|
72
75
|
outputScanner: true,
|
|
@@ -88,6 +91,6 @@ export function resolveLocale(config: ShellWardConfig): ResolvedLocale {
|
|
|
88
91
|
if (config.locale === 'zh') return 'zh'
|
|
89
92
|
if (config.locale === 'en') return 'en'
|
|
90
93
|
// auto detection
|
|
91
|
-
const lang = process.env.LANG || process.env.
|
|
92
|
-
return /
|
|
94
|
+
const lang = process.env.LANG || process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANGUAGE || ''
|
|
95
|
+
return /\bzh[_-]|chinese/i.test(lang) ? 'zh' : 'en'
|
|
93
96
|
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// src/update-check.ts — Non-blocking version check + remote vulnerability DB
|
|
2
|
+
// Uses only Node.js built-in https module (zero dependencies)
|
|
3
|
+
//
|
|
4
|
+
// Anti-annoyance design:
|
|
5
|
+
// - Network check at most once per 24 hours
|
|
6
|
+
// - Same version update only notified ONCE (dismissed = silenced until next version)
|
|
7
|
+
// - Vuln DB cached 24h, /check-updates always shows latest cache
|
|
8
|
+
// - All network failures are silent and cached to avoid repeated timeouts
|
|
9
|
+
|
|
10
|
+
import { get } from 'https'
|
|
11
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'fs'
|
|
12
|
+
import { join } from 'path'
|
|
13
|
+
import { getHomeDir } from './utils'
|
|
14
|
+
|
|
15
|
+
const CACHE_DIR = join(getHomeDir(), '.openclaw', 'shellward')
|
|
16
|
+
const CACHE_FILE = join(CACHE_DIR, 'update-cache.json')
|
|
17
|
+
const VULN_CACHE_FILE = join(CACHE_DIR, 'vuln-db-cache.json')
|
|
18
|
+
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000 // 24 hours
|
|
19
|
+
|
|
20
|
+
// Remote sources
|
|
21
|
+
const NPM_REGISTRY_URL = 'https://registry.npmjs.org/shellward/latest'
|
|
22
|
+
const VULN_DB_URL = 'https://raw.githubusercontent.com/jnMetaCode/shellward/main/vuln-db.json'
|
|
23
|
+
|
|
24
|
+
interface UpdateCache {
|
|
25
|
+
lastCheck: number
|
|
26
|
+
latestVersion: string | null
|
|
27
|
+
notifiedVersion: string | null // version user was already notified about — won't repeat
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface VulnEntry {
|
|
31
|
+
affectedBelow: string
|
|
32
|
+
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM'
|
|
33
|
+
id: string
|
|
34
|
+
ghsa?: string
|
|
35
|
+
description_zh: string
|
|
36
|
+
description_en: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SupplyChainAlert {
|
|
40
|
+
id: string
|
|
41
|
+
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM'
|
|
42
|
+
date: string
|
|
43
|
+
description_zh: string
|
|
44
|
+
description_en: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Simple HTTPS GET with redirect support. Timeout: 5s.
|
|
49
|
+
*/
|
|
50
|
+
function httpsGet(url: string): Promise<string> {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
const req = get(url, { timeout: 5000 }, (res) => {
|
|
53
|
+
if ((res.statusCode === 301 || res.statusCode === 302) && res.headers.location) {
|
|
54
|
+
get(res.headers.location, { timeout: 5000 }, (res2) => {
|
|
55
|
+
let data = ''
|
|
56
|
+
res2.on('data', (chunk: Buffer) => { data += chunk.toString() })
|
|
57
|
+
res2.on('end', () => resolve(data))
|
|
58
|
+
res2.on('error', reject)
|
|
59
|
+
}).on('error', reject)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
if (res.statusCode !== 200) {
|
|
63
|
+
reject(new Error(`HTTP ${res.statusCode}`))
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
let data = ''
|
|
67
|
+
res.on('data', (chunk: Buffer) => { data += chunk.toString() })
|
|
68
|
+
res.on('end', () => resolve(data))
|
|
69
|
+
res.on('error', reject)
|
|
70
|
+
})
|
|
71
|
+
req.on('error', reject)
|
|
72
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')) })
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Check npm for latest version.
|
|
78
|
+
*
|
|
79
|
+
* Returns result with `shouldNotify`:
|
|
80
|
+
* - true = first time seeing this new version, show the message
|
|
81
|
+
* - false = already notified for this version, stay quiet
|
|
82
|
+
* Returns null if check skipped or failed.
|
|
83
|
+
*/
|
|
84
|
+
export async function checkForUpdate(currentVersion: string): Promise<{
|
|
85
|
+
current: string
|
|
86
|
+
latest: string
|
|
87
|
+
updateAvailable: boolean
|
|
88
|
+
shouldNotify: boolean
|
|
89
|
+
} | null> {
|
|
90
|
+
try {
|
|
91
|
+
const cache = readCache<UpdateCache>(CACHE_FILE)
|
|
92
|
+
|
|
93
|
+
// Use cached version if within interval
|
|
94
|
+
let latest: string | null = null
|
|
95
|
+
if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS && cache.latestVersion) {
|
|
96
|
+
latest = cache.latestVersion
|
|
97
|
+
} else {
|
|
98
|
+
// Fetch from npm
|
|
99
|
+
const body = await httpsGet(NPM_REGISTRY_URL)
|
|
100
|
+
const data = JSON.parse(body)
|
|
101
|
+
latest = data.version
|
|
102
|
+
if (!latest || typeof latest !== 'string') return null
|
|
103
|
+
|
|
104
|
+
// Save to cache (preserve notifiedVersion)
|
|
105
|
+
writeCache(CACHE_FILE, {
|
|
106
|
+
lastCheck: Date.now(),
|
|
107
|
+
latestVersion: latest,
|
|
108
|
+
notifiedVersion: cache?.notifiedVersion || null,
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const updateAvailable = compareVersions(latest, currentVersion) > 0
|
|
113
|
+
|
|
114
|
+
// Determine if we should notify:
|
|
115
|
+
// Only notify if update available AND we haven't already notified for this exact version
|
|
116
|
+
const alreadyNotified = cache?.notifiedVersion === latest
|
|
117
|
+
const shouldNotify = updateAvailable && !alreadyNotified
|
|
118
|
+
|
|
119
|
+
// If we're going to notify, mark it so we don't repeat
|
|
120
|
+
if (shouldNotify) {
|
|
121
|
+
const freshCache = readCache<UpdateCache>(CACHE_FILE) || { lastCheck: Date.now(), latestVersion: latest, notifiedVersion: null }
|
|
122
|
+
freshCache.notifiedVersion = latest
|
|
123
|
+
writeCache(CACHE_FILE, freshCache)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return { current: currentVersion, latest, updateAvailable, shouldNotify }
|
|
127
|
+
} catch {
|
|
128
|
+
return null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Fetch remote vulnerability database. Cached 24h. Local fallback on failure.
|
|
134
|
+
*/
|
|
135
|
+
export async function fetchVulnDB(): Promise<{ vulns: VulnEntry[]; alerts: SupplyChainAlert[] }> {
|
|
136
|
+
try {
|
|
137
|
+
const cached = readCache<{ lastCheck: number; vulns: VulnEntry[]; alerts: SupplyChainAlert[] }>(VULN_CACHE_FILE)
|
|
138
|
+
if (cached && Date.now() - cached.lastCheck < CHECK_INTERVAL_MS && cached.vulns) {
|
|
139
|
+
return { vulns: cached.vulns, alerts: cached.alerts || [] }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const body = await httpsGet(VULN_DB_URL)
|
|
143
|
+
const data = JSON.parse(body)
|
|
144
|
+
const vulns: VulnEntry[] = Array.isArray(data.vulnerabilities) ? data.vulnerabilities : []
|
|
145
|
+
const alerts: SupplyChainAlert[] = Array.isArray(data.supplyChainAlerts) ? data.supplyChainAlerts : []
|
|
146
|
+
|
|
147
|
+
writeCache(VULN_CACHE_FILE, { lastCheck: Date.now(), vulns, alerts })
|
|
148
|
+
return { vulns, alerts }
|
|
149
|
+
} catch {
|
|
150
|
+
// Cache failure result to avoid repeated timeouts
|
|
151
|
+
const cached = readCache<{ vulns: VulnEntry[]; alerts: SupplyChainAlert[] }>(VULN_CACHE_FILE)
|
|
152
|
+
const fallback = { vulns: cached?.vulns || [], alerts: cached?.alerts || [] }
|
|
153
|
+
writeCache(VULN_CACHE_FILE, { lastCheck: Date.now(), ...fallback })
|
|
154
|
+
return fallback
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Compare semver-like version strings. Positive if a > b, negative if a < b, 0 if equal.
|
|
160
|
+
*/
|
|
161
|
+
export function compareVersions(a: string, b: string): number {
|
|
162
|
+
const pa = a.split('.').map(Number)
|
|
163
|
+
const pb = b.split('.').map(Number)
|
|
164
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
165
|
+
const diff = (pa[i] || 0) - (pb[i] || 0)
|
|
166
|
+
if (diff !== 0) return diff
|
|
167
|
+
}
|
|
168
|
+
return 0
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ===== Cache helpers =====
|
|
172
|
+
|
|
173
|
+
function readCache<T>(path: string): T | null {
|
|
174
|
+
try {
|
|
175
|
+
return JSON.parse(readFileSync(path, 'utf-8')) as T
|
|
176
|
+
} catch {
|
|
177
|
+
return null
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function writeCache(path: string, data: unknown): void {
|
|
182
|
+
try {
|
|
183
|
+
mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 })
|
|
184
|
+
writeFileSync(path, JSON.stringify(data), { mode: 0o600 })
|
|
185
|
+
} catch { /* ignore */ }
|
|
186
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// src/utils.ts — Cross-platform path helpers
|
|
2
|
+
|
|
3
|
+
import { homedir } from 'os'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get user home directory. Works on Windows (USERPROFILE), Linux/macOS (HOME).
|
|
7
|
+
*/
|
|
8
|
+
export function getHomeDir(): string {
|
|
9
|
+
return homedir() || process.env.HOME || process.env.USERPROFILE || '~'
|
|
10
|
+
}
|
package/vuln-db.json
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 2,
|
|
3
|
+
"lastUpdated": "2026-03-12T00:00:00Z",
|
|
4
|
+
"source": "ShellWard Security Team — aggregated from NVD, GitHub Advisories, security research",
|
|
5
|
+
"vulnerabilities": [
|
|
6
|
+
{
|
|
7
|
+
"affectedBelow": "1.0.111",
|
|
8
|
+
"severity": "HIGH",
|
|
9
|
+
"id": "CVE-2025-59536",
|
|
10
|
+
"ghsa": "GHSA-ph6w-f82w-28w6",
|
|
11
|
+
"description_zh": "远程代码执行:恶意仓库通过 Hooks 和 MCP Server 在信任提示前执行任意命令 (CVSS 8.7)",
|
|
12
|
+
"description_en": "RCE via Hooks and MCP Server bypass — arbitrary shell execution before trust dialog (CVSS 8.7)"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"affectedBelow": "2.0.65",
|
|
16
|
+
"severity": "MEDIUM",
|
|
17
|
+
"id": "CVE-2026-21852",
|
|
18
|
+
"ghsa": "GHSA-jh7p-qr78-84p7",
|
|
19
|
+
"description_zh": "API 密钥泄露:恶意仓库通过 settings.json 设置 ANTHROPIC_BASE_URL 窃取用户 API Key (CVSS 5.3)",
|
|
20
|
+
"description_en": "API key exfiltration via ANTHROPIC_BASE_URL in settings.json before trust prompt (CVSS 5.3)"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"affectedBelow": "2026.2.7",
|
|
24
|
+
"severity": "HIGH",
|
|
25
|
+
"id": "GHSA-66q4-vfjg-2qhh",
|
|
26
|
+
"description_zh": "命令注入:通过目录切换绕过文件写入保护",
|
|
27
|
+
"description_en": "Command injection via directory change bypasses write protection"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"affectedBelow": "2026.2.7",
|
|
31
|
+
"severity": "HIGH",
|
|
32
|
+
"id": "GHSA-mhg7-666j-cqg4",
|
|
33
|
+
"description_zh": "命令注入:通过管道 sed 命令绕过文件写入限制",
|
|
34
|
+
"description_en": "Command injection via piped sed command bypasses file write restrictions"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"affectedBelow": "2026.2.7",
|
|
38
|
+
"severity": "HIGH",
|
|
39
|
+
"id": "GHSA-ff64-7w26-62rf",
|
|
40
|
+
"description_zh": "沙箱逃逸:通过 settings.json 持久化配置注入",
|
|
41
|
+
"description_en": "Sandbox escape via persistent configuration injection in settings.json"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"affectedBelow": "2026.2.4",
|
|
45
|
+
"severity": "HIGH",
|
|
46
|
+
"id": "GHSA-qgqw-h4xq-7w8w",
|
|
47
|
+
"description_zh": "命令注入:find 命令绕过用户审批提示",
|
|
48
|
+
"description_en": "Command injection in find command bypasses user approval prompt"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"affectedBelow": "2026.2.4",
|
|
52
|
+
"severity": "HIGH",
|
|
53
|
+
"id": "GHSA-q728-gf8j-w49r",
|
|
54
|
+
"description_zh": "路径绕过:通过 ZSH clobber 实现任意文件写入",
|
|
55
|
+
"description_en": "Path restriction bypass via ZSH clobber allows arbitrary file writes"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"affectedBelow": "2026.2.4",
|
|
59
|
+
"severity": "HIGH",
|
|
60
|
+
"id": "GHSA-vhw5-3g5m-8ggf",
|
|
61
|
+
"description_zh": "域名验证绕过:自动向攻击者控制的域名发送请求",
|
|
62
|
+
"description_en": "Domain validation bypass allows automatic requests to attacker-controlled domains"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"affectedBelow": "1.0.131",
|
|
66
|
+
"severity": "HIGH",
|
|
67
|
+
"id": "GHSA-xq4m-mc3c-vvg3",
|
|
68
|
+
"description_zh": "命令验证绕过:允许执行任意代码",
|
|
69
|
+
"description_en": "Command validation bypass allows arbitrary code execution"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"affectedBelow": "1.0.120",
|
|
73
|
+
"severity": "HIGH",
|
|
74
|
+
"id": "GHSA-5hhx-v7f6-x7gv",
|
|
75
|
+
"description_zh": "信任提示前执行命令:启动时即执行恶意代码",
|
|
76
|
+
"description_en": "Command execution prior to startup trust dialog"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"affectedBelow": "1.0.120",
|
|
80
|
+
"severity": "HIGH",
|
|
81
|
+
"id": "GHSA-7mv8-j34q-vp7q",
|
|
82
|
+
"description_zh": "sed 命令验证绕过:实现任意文件写入",
|
|
83
|
+
"description_en": "Sed command validation bypass allows arbitrary file writes"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"affectedBelow": "1.0.111",
|
|
87
|
+
"severity": "HIGH",
|
|
88
|
+
"id": "GHSA-2jjv-qf24-vfm4",
|
|
89
|
+
"description_zh": "特定 Yarn 版本下插件自动加载导致任意代码执行",
|
|
90
|
+
"description_en": "Arbitrary code execution via plugin autoloading with specific Yarn versions"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"affectedBelow": "1.0.102",
|
|
94
|
+
"severity": "HIGH",
|
|
95
|
+
"id": "GHSA-j4h9-wv2m-wrf7",
|
|
96
|
+
"description_zh": "恶意 git email 配置导致任意代码执行",
|
|
97
|
+
"description_en": "Arbitrary code execution caused by maliciously configured git email"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"affectedBelow": "1.0.102",
|
|
101
|
+
"severity": "HIGH",
|
|
102
|
+
"id": "GHSA-qxfv-fcpc-w36x",
|
|
103
|
+
"description_zh": "rg 命令注入绕过用户审批提示",
|
|
104
|
+
"description_en": "Command injection in rg command bypassed user approval prompt"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"affectedBelow": "1.0.87",
|
|
108
|
+
"severity": "HIGH",
|
|
109
|
+
"id": "GHSA-x5gv-jw7f-j6xj",
|
|
110
|
+
"description_zh": "默认允许列表过于宽松:未授权文件读取和网络外泄",
|
|
111
|
+
"description_en": "Permissive default allowlist enables unauthorized file read and network exfiltration"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"affectedBelow": "1.0.82",
|
|
115
|
+
"severity": "HIGH",
|
|
116
|
+
"id": "GHSA-x56v-x2h6-7j34",
|
|
117
|
+
"description_zh": "echo 命令注入绕过用户审批提示",
|
|
118
|
+
"description_en": "Command injection in echo command bypassed user approval prompt"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"affectedBelow": "1.0.3",
|
|
122
|
+
"severity": "HIGH",
|
|
123
|
+
"id": "GHSA-9f65-56v6-gxw7",
|
|
124
|
+
"description_zh": "IDE 扩展 WebSocket 接受任意来源连接",
|
|
125
|
+
"description_en": "IDE extensions allow websocket connections from arbitrary origins"
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"supplyChainAlerts": [
|
|
129
|
+
{
|
|
130
|
+
"id": "SW-ALERT-2026-001",
|
|
131
|
+
"severity": "HIGH",
|
|
132
|
+
"date": "2026-02-15",
|
|
133
|
+
"description_zh": "SANDWORM_MODE 供应链攻击:19 个恶意 npm 包伪装为 Claude Code 等 AI 工具,植入恶意 MCP Server 窃取 SSH 密钥和凭证",
|
|
134
|
+
"description_en": "SANDWORM_MODE supply chain attack: 19 malicious npm packages impersonating Claude Code and AI tools, deploying rogue MCP servers to exfiltrate SSH keys and credentials"
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|