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.
@@ -0,0 +1,46 @@
1
+ // src/layers/session-guard.ts — L8: Session lifecycle security
2
+ // Uses: session_end (security summary), subagent_spawning (enforce policies)
3
+
4
+ import { resolveLocale } from '../types'
5
+ import type { ShellWardConfig } from '../types'
6
+ import type { AuditLog } from '../audit-log'
7
+
8
+ export function setupSessionGuard(
9
+ api: any,
10
+ config: ShellWardConfig,
11
+ log: AuditLog,
12
+ enforce: boolean,
13
+ ) {
14
+ const locale = resolveLocale(config)
15
+
16
+ // === Session end: generate security summary ===
17
+ api.on('session_end', () => {
18
+ log.write({
19
+ level: 'INFO',
20
+ layer: 'L8',
21
+ action: 'detect',
22
+ detail: locale === 'zh'
23
+ ? '会话结束 — 安全审计完成'
24
+ : 'Session ended — security audit complete',
25
+ })
26
+ }, { name: 'shellward.session-end', priority: 50 })
27
+
28
+ // === Subagent spawning: enforce security policies ===
29
+ api.on('subagent_spawning', (event: any) => {
30
+ const mode = event.mode || 'unknown'
31
+
32
+ log.write({
33
+ level: 'MEDIUM',
34
+ layer: 'L8',
35
+ action: 'detect',
36
+ detail: locale === 'zh'
37
+ ? `子 Agent 创建: mode=${mode}, agentId=${event.agentId || 'unknown'}`
38
+ : `Subagent spawning: mode=${mode}, agentId=${event.agentId || 'unknown'}`,
39
+ })
40
+
41
+ // In strict mode, could block subagent spawning entirely
42
+ // For now, just audit
43
+ }, { name: 'shellward.subagent-guard', priority: 100 })
44
+
45
+ api.logger.info('[ShellWard] L8 Session Guard enabled')
46
+ }
@@ -0,0 +1,182 @@
1
+ // src/layers/tool-blocker.ts — L3: Block dangerous tool calls via before_tool_call hook
2
+
3
+ import { DANGEROUS_COMMANDS, splitCommands } from '../rules/dangerous-commands'
4
+ import { PROTECTED_PATHS } from '../rules/protected-paths'
5
+ import { resolveLocale } from '../types'
6
+ import type { ShellWardConfig, ResolvedLocale } from '../types'
7
+ import type { AuditLog } from '../audit-log'
8
+ import { resolve } from 'path'
9
+
10
+ // Tools that are always blocked (lowercase for case-insensitive matching)
11
+ const BLOCKED_TOOLS = new Set([
12
+ 'payment', 'transfer', 'purchase',
13
+ 'stripe_charge', 'paypal_send',
14
+ ])
15
+
16
+ // Tools that get logged but not blocked (lowercase)
17
+ const SENSITIVE_TOOLS = new Set([
18
+ 'send_email', 'delete_email',
19
+ 'send_message', 'post_tweet',
20
+ 'file_delete', 'skill_install',
21
+ ])
22
+
23
+ // Tool names that execute shell commands (lowercase)
24
+ const EXEC_TOOLS = new Set([
25
+ 'exec', 'shell_exec', 'run_command', 'bash',
26
+ ])
27
+
28
+ export function setupToolBlocker(
29
+ api: any,
30
+ config: ShellWardConfig,
31
+ log: AuditLog,
32
+ enforce: boolean,
33
+ ) {
34
+ const locale = resolveLocale(config)
35
+
36
+ api.on('before_tool_call', (event: any) => {
37
+ const tool: string = event.toolName || ''
38
+ const toolLower = tool.toLowerCase()
39
+ const args: Record<string, any> = event.params || {}
40
+
41
+ // 1. Always-blocked tools (case-insensitive)
42
+ if (BLOCKED_TOOLS.has(toolLower)) {
43
+ const reason = locale === 'zh'
44
+ ? `安全策略禁止自动执行: ${tool}`
45
+ : `Blocked by security policy: ${tool}`
46
+
47
+ log.write({
48
+ level: 'CRITICAL',
49
+ layer: 'L3',
50
+ action: enforce ? 'block' : 'detect',
51
+ detail: reason,
52
+ tool,
53
+ })
54
+
55
+ if (enforce) {
56
+ return { block: true, blockReason: `🚫 [ShellWard] ${reason}` }
57
+ }
58
+ return
59
+ }
60
+
61
+ // 2. Dangerous shell command detection (case-insensitive tool match)
62
+ if (EXEC_TOOLS.has(toolLower)) {
63
+ const rawCmd = args.command ?? args.cmd ?? ''
64
+ const cmd = typeof rawCmd === 'string' ? rawCmd : ''
65
+ // Split on command separators to catch chained attacks like "echo hi; rm -rf /"
66
+ const parts = splitCommands(cmd)
67
+ for (const part of parts) {
68
+ const result = checkDangerousCommand(part, locale, tool, log, enforce)
69
+ if (result) return result
70
+ }
71
+ }
72
+
73
+ // 3. Protected path detection (normalize path first)
74
+ const rawPath = String(args.path || args.file_path || args.filename || args.target || '')
75
+ if (rawPath && isWriteOrDeleteTool(toolLower)) {
76
+ // Resolve path to prevent ../ traversal bypass
77
+ const normalizedPath = normalizePath(rawPath)
78
+ const result = checkProtectedPath(normalizedPath, locale, tool, log, enforce)
79
+ if (result) return result
80
+ }
81
+
82
+ // 4. Log sensitive tool usage (case-insensitive)
83
+ if (SENSITIVE_TOOLS.has(toolLower)) {
84
+ log.write({
85
+ level: 'MEDIUM',
86
+ layer: 'L3',
87
+ action: 'detect',
88
+ detail: `Sensitive tool used: ${tool}`,
89
+ tool,
90
+ })
91
+ }
92
+
93
+ }, { name: 'shellward.tool-blocker', priority: 200 })
94
+
95
+ api.logger.info('[ShellWard] L3 Tool Blocker enabled')
96
+ }
97
+
98
+ function checkDangerousCommand(
99
+ cmd: string,
100
+ locale: ResolvedLocale,
101
+ tool: string,
102
+ log: AuditLog,
103
+ enforce: boolean,
104
+ ): { block: true; blockReason: string } | undefined {
105
+ for (const rule of DANGEROUS_COMMANDS) {
106
+ if (rule.pattern.test(cmd)) {
107
+ const desc = locale === 'zh' ? rule.description_zh : rule.description_en
108
+ const reason = locale === 'zh'
109
+ ? `检测到危险命令: ${truncate(cmd, 80)}\n原因: ${desc}`
110
+ : `Dangerous command: ${truncate(cmd, 80)}\nReason: ${desc}`
111
+
112
+ log.write({
113
+ level: 'CRITICAL',
114
+ layer: 'L3',
115
+ action: enforce ? 'block' : 'detect',
116
+ detail: reason,
117
+ tool,
118
+ pattern: rule.id,
119
+ })
120
+
121
+ if (enforce) {
122
+ return { block: true, blockReason: `🚫 [ShellWard] ${reason}` }
123
+ }
124
+ return
125
+ }
126
+ }
127
+ }
128
+
129
+ function checkProtectedPath(
130
+ path: string,
131
+ locale: ResolvedLocale,
132
+ tool: string,
133
+ log: AuditLog,
134
+ enforce: boolean,
135
+ ): { block: true; blockReason: string } | undefined {
136
+ for (const rule of PROTECTED_PATHS) {
137
+ if (rule.pattern.test(path)) {
138
+ const desc = locale === 'zh' ? rule.description_zh : rule.description_en
139
+ const reason = locale === 'zh'
140
+ ? `禁止操作受保护路径: ${path}\n原因: ${desc}`
141
+ : `Protected path blocked: ${path}\nReason: ${desc}`
142
+
143
+ log.write({
144
+ level: 'HIGH',
145
+ layer: 'L3',
146
+ action: enforce ? 'block' : 'detect',
147
+ detail: reason,
148
+ tool,
149
+ pattern: rule.id,
150
+ })
151
+
152
+ if (enforce) {
153
+ return { block: true, blockReason: `🚫 [ShellWard] ${reason}` }
154
+ }
155
+ return
156
+ }
157
+ }
158
+ }
159
+
160
+ function isWriteOrDeleteTool(toolLower: string): boolean {
161
+ return /write|delete|remove|overwrite|truncate|edit/.test(toolLower)
162
+ }
163
+
164
+ /**
165
+ * Normalize path: resolve ../ traversal, expand ~, lowercase for comparison
166
+ */
167
+ function normalizePath(p: string): string {
168
+ // Expand ~ to HOME
169
+ const expanded = p.startsWith('~')
170
+ ? p.replace(/^~/, process.env.HOME || '/root')
171
+ : p
172
+ // Resolve ../ and ./ sequences
173
+ try {
174
+ return resolve(expanded)
175
+ } catch {
176
+ return expanded
177
+ }
178
+ }
179
+
180
+ function truncate(s: string, max: number): string {
181
+ return s.length > max ? s.slice(0, max) + '...' : s
182
+ }
@@ -0,0 +1,105 @@
1
+ // src/rules/dangerous-commands.ts — Shell command blocklist (bilingual)
2
+
3
+ import type { DangerousCommandRule } from '../types'
4
+
5
+ export const DANGEROUS_COMMANDS: DangerousCommandRule[] = [
6
+ {
7
+ id: 'rm_rf_root',
8
+ pattern: /rm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+-[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*\s+-[a-zA-Z]*r|-[a-zA-Z]*rf[a-zA-Z]*)\s+[\/~]/i,
9
+ description_zh: '递归强制删除根目录或用户目录',
10
+ description_en: 'Recursive force delete on root or home directory',
11
+ },
12
+ {
13
+ id: 'rm_rf_wildcard',
14
+ pattern: /rm\s+(-[a-zA-Z]*rf|-[a-zA-Z]*fr)\s+\*/i,
15
+ description_zh: '递归强制删除通配符匹配的所有文件',
16
+ description_en: 'Recursive force delete with wildcard',
17
+ },
18
+ {
19
+ id: 'mkfs',
20
+ pattern: /mkfs\b/i,
21
+ description_zh: '格式化磁盘',
22
+ description_en: 'Format disk partition',
23
+ },
24
+ {
25
+ id: 'dd_if',
26
+ pattern: /dd\s+if=/i,
27
+ description_zh: '低级磁盘操作(可能覆盖磁盘数据)',
28
+ description_en: 'Low-level disk operation (may overwrite data)',
29
+ },
30
+ {
31
+ id: 'curl_pipe_sh',
32
+ pattern: /curl\s+[^|]*\|\s*(?:sudo\s+)?(?:ba)?sh/i,
33
+ description_zh: '从网络下载并直接执行脚本',
34
+ description_en: 'Download and pipe to shell execution',
35
+ },
36
+ {
37
+ id: 'wget_pipe_sh',
38
+ pattern: /wget\s+[^|]*\|\s*(?:sudo\s+)?(?:ba)?sh/i,
39
+ description_zh: '从网络下载并直接执行脚本',
40
+ description_en: 'Download and pipe to shell execution',
41
+ },
42
+ {
43
+ id: 'dev_write',
44
+ pattern: />\s*\/dev\/[sh]d[a-z]/i,
45
+ description_zh: '直接写入磁盘设备',
46
+ description_en: 'Direct write to disk device',
47
+ },
48
+ {
49
+ id: 'chmod_777',
50
+ pattern: /chmod\s+(-[a-zA-Z]*\s+)?777(?:\s|$)/i,
51
+ description_zh: '设置全局可读写可执行权限',
52
+ description_en: 'Set world-readable/writable/executable permissions',
53
+ },
54
+ {
55
+ id: 'kill_all',
56
+ pattern: /killall\s+-9|kill\s+-9\s+-1/i,
57
+ description_zh: '强制终止所有进程',
58
+ description_en: 'Force kill all processes',
59
+ },
60
+ {
61
+ id: 'iptables_flush',
62
+ pattern: /iptables\s+-F/i,
63
+ description_zh: '清空防火墙规则',
64
+ description_en: 'Flush all firewall rules',
65
+ },
66
+ {
67
+ id: 'history_clear',
68
+ pattern: /history\s+-c|>\s*~\/\.bash_history|>\s*~\/\.zsh_history/i,
69
+ description_zh: '清除命令历史(可能是攻击后清痕迹)',
70
+ description_en: 'Clear command history (potential post-attack cleanup)',
71
+ },
72
+ {
73
+ id: 'fork_bomb',
74
+ pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;|\.\/[a-z]+\s*&\s*\.\/[a-z]+/i,
75
+ description_zh: 'Fork 炸弹(耗尽系统资源)',
76
+ description_en: 'Fork bomb (exhaust system resources)',
77
+ },
78
+ {
79
+ id: 'eval_base64',
80
+ pattern: /eval\s+.*(?:base64|atob)|base64\s+-d.*\|\s*(?:ba)?sh/i,
81
+ description_zh: 'Base64 解码后执行(混淆攻击)',
82
+ description_en: 'Base64 decode and execute (obfuscated attack)',
83
+ },
84
+ {
85
+ id: 'reverse_shell',
86
+ pattern: /\/dev\/tcp\/|nc\s+-[a-zA-Z]*e\s|ncat\s.*-e\s|bash\s+-i\s+>&\s*\/dev/i,
87
+ description_zh: '反弹 Shell(远程控制)',
88
+ description_en: 'Reverse shell (remote control)',
89
+ },
90
+ {
91
+ id: 'crontab_overwrite',
92
+ pattern: /crontab\s+-r|echo\s+.*>\s*\/var\/spool\/cron/i,
93
+ description_zh: '覆盖或删除定时任务',
94
+ description_en: 'Overwrite or remove crontab entries',
95
+ },
96
+ ]
97
+
98
+ /**
99
+ * Normalize command string before pattern matching:
100
+ * - Split on command separators (;, &&, ||, \n) and check each part
101
+ * - Trim whitespace
102
+ */
103
+ export function splitCommands(cmd: string): string[] {
104
+ return cmd.split(/\s*(?:;|&&|\|\||[\r\n]+)\s*/).filter(Boolean)
105
+ }
@@ -0,0 +1,102 @@
1
+ // src/rules/injection-en.ts — English prompt injection detection rules
2
+
3
+ import type { InjectionRule } from '../types'
4
+
5
+ export const INJECTION_RULES_EN: InjectionRule[] = [
6
+ {
7
+ id: 'en_ignore_prev',
8
+ name: 'Ignore previous instructions',
9
+ pattern: 'ignore\\s+(?:all\\s+)?(?:previous|prior|above|earlier|preceding)\\s+(?:instructions?|rules?|prompts?|guidelines?|constraints?)',
10
+ flags: 'i',
11
+ riskScore: 40,
12
+ category: 'override',
13
+ },
14
+ {
15
+ id: 'en_new_role',
16
+ name: 'Role hijack',
17
+ pattern: '(?:you\\s+are\\s+now|from\\s+now\\s+on\\s+you\\s+are|act\\s+as|pretend\\s+(?:to\\s+be|you\\s+are)|imagine\\s+you\\s+are)\\s+(?:a\\s+)?',
18
+ flags: 'i',
19
+ riskScore: 35,
20
+ category: 'role_hijack',
21
+ },
22
+ {
23
+ id: 'en_system_prompt',
24
+ name: 'System prompt extraction',
25
+ pattern: '(?:output|print|show|reveal|display|repeat|leak|dump)\\s+(?:your\\s+)?(?:system|initial|original|full)?\\s*(?:prompt|instructions?|rules?|guidelines?)',
26
+ flags: 'i',
27
+ riskScore: 30,
28
+ category: 'exfiltration',
29
+ },
30
+ {
31
+ id: 'en_developer_mode',
32
+ name: 'Developer/admin mode',
33
+ pattern: '(?:enter|enable|activate|switch\\s+to)\\s+(?:developer|debug|admin|root|sudo|maintenance|god)\\s+(?:mode|access|privileges?)',
34
+ flags: 'i',
35
+ riskScore: 35,
36
+ category: 'privilege_escalation',
37
+ },
38
+ {
39
+ id: 'en_no_restriction',
40
+ name: 'Remove restrictions',
41
+ pattern: '(?:remove|disable|turn\\s+off|bypass|ignore|skip|override|circumvent)\\s+(?:all\\s+)?(?:restrictions?|constraints?|safety|filters?|guardrails?|limitations?|safeguards?)',
42
+ flags: 'i',
43
+ riskScore: 40,
44
+ category: 'override',
45
+ },
46
+ {
47
+ id: 'en_do_anything',
48
+ name: 'Do Anything Now (DAN)',
49
+ pattern: '(?:DAN|do\\s+anything\\s+now|jailbreak|uncensored|unfiltered)\\s*(?:mode|prompt)?',
50
+ flags: 'i',
51
+ riskScore: 40,
52
+ category: 'jailbreak',
53
+ },
54
+ {
55
+ id: 'en_boundary_marker',
56
+ name: 'Boundary marker injection',
57
+ pattern: '(?:<<|\\[\\[|\\{\\{)\\s*(?:SYSTEM|SYS|END|NEW\\s*INSTRUCTION|OVERRIDE|ADMIN)\\s*(?:>>|\\]\\]|\\}\\})',
58
+ flags: 'i',
59
+ riskScore: 30,
60
+ category: 'injection',
61
+ },
62
+ {
63
+ id: 'en_hidden_instruction',
64
+ name: 'Hidden instruction marker',
65
+ pattern: '(?:the\\s+following\\s+is\\s+(?:a\\s+)?)?(?:hidden|secret|real|actual|true)\\s+(?:instruction|command|prompt|directive)',
66
+ flags: 'i',
67
+ riskScore: 35,
68
+ category: 'injection',
69
+ },
70
+ {
71
+ id: 'en_data_exfil',
72
+ name: 'Data exfiltration',
73
+ pattern: '(?:send|transmit|upload|forward|post|exfiltrate)\\s+(?:all\\s+)?(?:conversation|chat|messages?|history|data|files?|context)\\s+(?:to|via)',
74
+ flags: 'i',
75
+ riskScore: 40,
76
+ category: 'exfiltration',
77
+ },
78
+ {
79
+ id: 'en_never_refuse',
80
+ name: 'Never refuse',
81
+ pattern: '(?:never|do\\s+not|don\'t|cannot|must\\s+not)\\s+(?:refuse|decline|reject|say\\s+no|deny)',
82
+ flags: 'i',
83
+ riskScore: 25,
84
+ category: 'override',
85
+ },
86
+ {
87
+ id: 'en_encode_exfil',
88
+ name: 'Encoded exfiltration',
89
+ pattern: '(?:encode|encrypt|convert)\\s+(?:.*?)\\s+(?:in|to|as)\\s+(?:base64|hex|rot13|binary)',
90
+ flags: 'i',
91
+ riskScore: 25,
92
+ category: 'exfiltration',
93
+ },
94
+ {
95
+ id: 'en_markdown_injection',
96
+ name: 'Markdown image injection',
97
+ pattern: '!\\[\\s*[^\\]]*\\]\\(https?:\\/\\/[^)]*(?:callback|exfil|webhook|log)',
98
+ flags: 'i',
99
+ riskScore: 35,
100
+ category: 'exfiltration',
101
+ },
102
+ ]
@@ -0,0 +1,99 @@
1
+ // src/rules/injection-zh.ts — Chinese prompt injection detection rules
2
+
3
+ import type { InjectionRule } from '../types'
4
+
5
+ export const INJECTION_RULES_ZH: InjectionRule[] = [
6
+ {
7
+ id: 'zh_ignore_prev',
8
+ name: '忽略之前指令',
9
+ pattern: '(?:请|你要|现在)?忽略(?:之前|上面|以上|前面|所有)(?:的)?(?:指令|指示|规则|提示|要求|约束)',
10
+ riskScore: 40,
11
+ category: 'override',
12
+ },
13
+ {
14
+ id: 'zh_new_role',
15
+ name: '角色扮演攻击',
16
+ pattern: '(?:你现在是|你的新身份是|从现在起你是|假装你是|扮演|你是一个)(?:.*?)(?:助手|AI|机器人|黑客|专家)',
17
+ riskScore: 35,
18
+ category: 'role_hijack',
19
+ },
20
+ {
21
+ id: 'zh_system_prompt',
22
+ name: '系统提示窃取',
23
+ pattern: '(?:输出|显示|打印|告诉我|重复|泄露|展示)(?:你的)?(?:系统|初始|原始)?(?:提示词|system\\s*prompt|指令|规则|约束)',
24
+ riskScore: 30,
25
+ category: 'exfiltration',
26
+ },
27
+ {
28
+ id: 'zh_developer_mode',
29
+ name: '开发者模式',
30
+ pattern: '(?:进入|启用|开启|切换到)(?:开发者|调试|测试|管理员|root|超级)(?:模式|权限)',
31
+ riskScore: 35,
32
+ category: 'privilege_escalation',
33
+ },
34
+ {
35
+ id: 'zh_no_restriction',
36
+ name: '解除限制',
37
+ pattern: '(?:取消|移除|去掉|关闭|忽略|跳过|绕过)(?:所有|一切|你的)?(?:限制|约束|安全|过滤|审查|规则)',
38
+ riskScore: 40,
39
+ category: 'override',
40
+ },
41
+ {
42
+ id: 'zh_do_not_refuse',
43
+ name: '禁止拒绝',
44
+ pattern: '(?:不要|不许|不能|不可以|禁止你)(?:拒绝|拒绝回答|说不|推辞)',
45
+ riskScore: 25,
46
+ category: 'override',
47
+ },
48
+ {
49
+ id: 'zh_hidden_instruction',
50
+ name: '隐藏指令标记',
51
+ pattern: '(?:以下是|下面是)?(?:隐藏|秘密|真正的|实际的)(?:指令|命令|提示|任务)',
52
+ riskScore: 35,
53
+ category: 'injection',
54
+ },
55
+ {
56
+ id: 'zh_output_format_hijack',
57
+ name: '输出格式劫持',
58
+ pattern: '(?:只|仅|必须)?(?:输出|回复|返回|回答)(?:以下|如下|这个)(?:内容|文字|文本)',
59
+ riskScore: 15,
60
+ category: 'hijack',
61
+ },
62
+ {
63
+ id: 'zh_data_exfil',
64
+ name: '数据外泄',
65
+ pattern: '(?:把|将)(?:所有|全部)?(?:对话|聊天|消息|记录|历史|数据|文件)(?:发送|传输|上传|转发)(?:到|给)',
66
+ riskScore: 40,
67
+ category: 'exfiltration',
68
+ },
69
+ {
70
+ id: 'zh_boundary_marker',
71
+ name: '边界标记注入',
72
+ pattern: '(?:<<|\\[\\[|\\{\\{)\\s*(?:SYSTEM|系统|SYS|END|新指令|NEW)\\s*(?:>>|\\]\\]|\\}\\})',
73
+ riskScore: 30,
74
+ category: 'injection',
75
+ },
76
+ {
77
+ id: 'zh_act_as',
78
+ name: '行为替换',
79
+ pattern: '(?:请以|用|按照|模仿)(?:.*?)(?:的方式|的口吻|的风格|的身份)(?:回答|回复|说话|输出)',
80
+ riskScore: 20,
81
+ category: 'role_hijack',
82
+ },
83
+ {
84
+ id: 'zh_jailbreak',
85
+ name: '越狱关键词',
86
+ pattern: '(?:DAN|越狱|jailbreak|无限制模式|do\\s*anything\\s*now)',
87
+ flags: 'i',
88
+ riskScore: 40,
89
+ category: 'jailbreak',
90
+ },
91
+ {
92
+ id: 'zh_xml_tag_injection',
93
+ name: 'XML/标签注入',
94
+ pattern: '<\\s*(?:system|instruction|prompt|admin|override|设置|系统|指令)\\s*>',
95
+ flags: 'i',
96
+ riskScore: 30,
97
+ category: 'injection',
98
+ },
99
+ ]
@@ -0,0 +1,78 @@
1
+ // src/rules/protected-paths.ts — Paths that should not be written/deleted (bilingual)
2
+
3
+ import type { ProtectedPathRule } from '../types'
4
+
5
+ export const PROTECTED_PATHS: ProtectedPathRule[] = [
6
+ {
7
+ id: 'env_file',
8
+ pattern: /(?:^|\/)\.env(?:\.[a-zA-Z]+)?$/i,
9
+ description_zh: '环境变量文件(可能含密钥)',
10
+ description_en: 'Environment file (may contain secrets)',
11
+ },
12
+ {
13
+ id: 'ssh_dir',
14
+ pattern: /(?:^|\/)\.ssh\//i,
15
+ description_zh: 'SSH 密钥目录',
16
+ description_en: 'SSH key directory',
17
+ },
18
+ {
19
+ id: 'gnupg_dir',
20
+ pattern: /(?:^|\/)\.gnupg\//i,
21
+ description_zh: 'GPG 密钥目录',
22
+ description_en: 'GPG key directory',
23
+ },
24
+ {
25
+ id: 'aws_credentials',
26
+ pattern: /(?:^|\/)\.aws\/credentials$/i,
27
+ description_zh: 'AWS 凭证文件',
28
+ description_en: 'AWS credentials file',
29
+ },
30
+ {
31
+ id: 'kube_config',
32
+ pattern: /(?:^|\/)\.kube\/config$/i,
33
+ description_zh: 'Kubernetes 配置(含集群凭证)',
34
+ description_en: 'Kubernetes config (contains cluster credentials)',
35
+ },
36
+ {
37
+ id: 'docker_config',
38
+ pattern: /(?:^|\/)\.docker\/config\.json$/i,
39
+ description_zh: 'Docker 配置(可能含 registry 凭证)',
40
+ description_en: 'Docker config (may contain registry credentials)',
41
+ },
42
+ {
43
+ id: 'git_credentials',
44
+ pattern: /(?:^|\/)\.git-credentials$/i,
45
+ description_zh: 'Git 凭证文件',
46
+ description_en: 'Git credentials file',
47
+ },
48
+ {
49
+ id: 'npmrc',
50
+ pattern: /(?:^|\/)\.npmrc$/i,
51
+ description_zh: 'npm 配置(可能含 registry token)',
52
+ description_en: 'npm config (may contain registry token)',
53
+ },
54
+ {
55
+ id: 'private_key',
56
+ pattern: /(?:^|\/)(?:.*\.pem|.*\.key|.*_rsa|.*_ecdsa|.*_ed25519)$/i,
57
+ description_zh: '私钥文件',
58
+ description_en: 'Private key file',
59
+ },
60
+ {
61
+ id: 'etc_passwd',
62
+ pattern: /^\/etc\/(?:passwd|shadow|sudoers)/i,
63
+ description_zh: '系统认证文件',
64
+ description_en: 'System authentication file',
65
+ },
66
+ {
67
+ id: 'keychain',
68
+ pattern: /(?:^|\/)(?:Keychain|keychain|\.keystore|\.jks)$/i,
69
+ description_zh: '密钥链/密钥库文件',
70
+ description_en: 'Keychain/keystore file',
71
+ },
72
+ {
73
+ id: 'openclaw_config',
74
+ pattern: /(?:^|\/)\.openclaw\/(?:config|settings|credentials)/i,
75
+ description_zh: 'OpenClaw 配置和凭证',
76
+ description_en: 'OpenClaw config and credentials',
77
+ },
78
+ ]