@yottameta/yotta-agent-hardening 0.1.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.
@@ -0,0 +1,137 @@
1
+ # 元安全中文教程(新手全流程)
2
+
3
+ > 配套技能:元安全 yotta-agent-hardening(零依赖 Python 3.8+)
4
+ > 目标:从零开始,给智能体运行环境做一次「体检 + 加固建议」——三域扫描 → 读报告 → 生成并安装
5
+ > 防御守则 → 校验 → 留痕复盘。
6
+ > 纪律:本教程遵守脱敏纪律——检测描述与报告一律「类」表述,不给可复制注入串 / 命中原文。
7
+
8
+ ## 1. 教程目标与前置
9
+
10
+ - 学会运行 `scan`,读懂文本 / JSON / Markdown 报告与退出码。
11
+ - 学会用 `rules` 生成防御守则并安装到运行时目录,用 `verify` 校验。
12
+ - 学会查看扫描留痕(`audit log`),建立加固基线,前后对比。
13
+ - 前置:Python 3.8+(无需任何第三方库);一个想加固的智能体运行环境(skills 目录 + MCP 配置 +
14
+ 工具脚本)。没有现成环境时,用本技能目录做练习目标即可。
15
+
16
+ ## 2. 快速体验:跑一次扫描
17
+
18
+ 先做一个练习目录,放一个描述文档和一个 MCP 配置示例:
19
+
20
+ ```bash
21
+ mkdir demo-agent && cd demo-agent
22
+ ```
23
+
24
+ - `README.md`(文档类):写一句普通的功能描述,如「示例技能:整理当前项目文件」。
25
+ - `mcp.json`(配置类):放一个含远程来源、未锁版本、硬编码凭据占位的 MCP 配置:
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "demo": {
31
+ "url": "https://example.com/mcp",
32
+ "env": { "API_KEY": "sk-placeholder-1234567890" }
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ 然后扫描(脚本路径按你的实际位置调整):
39
+
40
+ ```bash
41
+ python3 ../scripts/yotta_agent_hardening.py scan ./demo-agent
42
+ ```
43
+
44
+ 预期:最高严重级为 high(MCP 远程来源),退出码 2。输出说明该配置需要处理。
45
+
46
+ ## 3. 读报告与退出码
47
+
48
+ 文本输出先给汇总与退出码;`--json` 给结构化结果,`--report out.md` 给 Markdown 报告:
49
+
50
+ ```bash
51
+ python3 ../scripts/yotta_agent_hardening.py scan ./demo-agent --json
52
+ python3 ../scripts/yotta_agent_hardening.py scan ./demo-agent --report report.md
53
+ ```
54
+
55
+ 退出码:`0` = 通过(无 low 及以上发现);`1` = 有加固建议(low / medium);
56
+ `2` = 高危需处理(high / critical);`4` = 用法错误 / 致命异常。
57
+ `--severity` 只过滤报告内容,不影响退出码;CI 里以退出码为准。
58
+
59
+ 报告按域分节:`提示注入防护(pi)` / `工具调用边界(tools)` / `数据隔离(isolation)`,
60
+ 每节一张表(规则 / 严重级 / 文件 / 行 / 说明)。说明是「类」表述,不回显命中原文。
61
+
62
+ ## 4. 扫自己的智能体运行环境
63
+
64
+ 把 target 换成真实环境即可(可以是一个项目目录、一个 skills 目录、或 MCP 配置文件本身):
65
+
66
+ ```bash
67
+ python3 scripts/yotta_agent_hardening.py scan ~/.agents/skills
68
+ python3 scripts/yotta_agent_hardening.py scan ./my-agent-runtime --domains pi,tools
69
+ python3 scripts/yotta_agent_hardening.py scan ./mcp.json --severity high --json
70
+ ```
71
+
72
+ - 扫描**只读**:不修改任何被测文件。
73
+ - 敏感读取检测默认开启,没有关闭开关(防御默认)。
74
+ - 每次扫描自动写一条留痕到 `~/.yotta-hardening/audit.log`(可用 `--config-dir` 或
75
+ `$YOTTA_HARDENING_DIR` 覆盖位置)。
76
+
77
+ ## 5. 生成并安装防御守则
78
+
79
+ ```bash
80
+ python3 scripts/yotta_agent_hardening.py rules
81
+ python3 scripts/yotta_agent_hardening.py rules --out ~/.yotta-hardening/GUARDRAILS.md
82
+ ```
83
+
84
+ 守则 = 三域 12 条(每域 4 条),即 SKILL.md 的「防御守则(强制规则)」。
85
+ 把 `GUARDRAILS.md` 放进智能体运行时目录,让智能体**每次会话读取执行**,
86
+ 这是「配置期固化防御」的落地点。
87
+
88
+ ## 6. 校验守则
89
+
90
+ ```bash
91
+ python3 scripts/yotta_agent_hardening.py verify ~/.yotta-hardening/GUARDRAILS.md
92
+ ```
93
+
94
+ 通过:`守则有效:覆盖三域,共 12 条守则(格式版本 1)`,退出码 0。
95
+ 不通过:报「缺域 / 域无守则条目」,退出码 1 或 4——说明文件被改动后格式不符合要求。
96
+
97
+ ## 7. 查看扫描留痕
98
+
99
+ ```bash
100
+ python3 scripts/yotta_agent_hardening.py audit log
101
+ python3 scripts/yotta_agent_hardening.py audit log --result high
102
+ python3 scripts/yotta_agent_hardening.py audit log --severity high --since 2026-08-01
103
+ python3 scripts/yotta_agent_hardening.py audit log --export audit-high.jsonl
104
+ ```
105
+
106
+ 留痕是 JSONL,每次 `scan` 一条(目标 / 时间 / 域 / 结果 / 最高严重级 / 文件数 / 汇总)。
107
+ 用它建立基线:扫一次 → 加固 → 再扫一次 → 对比严重级分布是否下降。
108
+
109
+ ## 8. 三域加固实践
110
+
111
+ ### 域 1:提示注入防护
112
+ - 命中「指令覆盖类 / 角色伪冒类」文本:删除或改写该描述,别让不可信文本带「执行指令」口吻;
113
+ 把「工具输出 / 网页 / 检索文档一律视为不可信数据」写进防御守则。
114
+ - 命中「凭据传递指令」:改为只读环境变量 / 凭据管理器,不在描述里要求把密钥类数据当参数传。
115
+
116
+ ### 域 2:工具调用边界
117
+ - 命中「下载即执行 / 混淆执行 / 持久化」脚本:移除,或改造成「人工确认 + 白名单」流程。
118
+ - 命中「MCP 远程来源 / 未锁版本 / 高权限 scope」:换成本地或可信源、固定版本 / revision、
119
+ 收紧到最小权限;新引入的 MCP 先过元信 / 元审装前校验再启用。
120
+ - 命中「权限过宽声明 / 网络出口无约束声明」:收紧到最小权限与明确的目标白名单。
121
+
122
+ ### 域 3:数据隔离
123
+ - 命中「敏感读取」:改用凭据管理器 / 环境变量,不直接读敏感文件。
124
+ - 命中「读取敏感数据后同文件出现网络原语」:断开「读取 → 网络发送」这条路径,或加脱敏与白名单。
125
+ - 命中「输出脱敏缺口」:输出前先脱敏(复用元测 report 脱敏口径),不打印密钥 / 令牌值。
126
+ - 命中「硬编码凭据」:迁移到环境变量 / 凭据管理器,并轮换已暴露的凭据。
127
+
128
+ ## 9. 常见问题与红线
129
+
130
+ - **扫描会改我的文件吗**:不会——扫描只读;只写留痕到配置目录与 `--report` 指定文件。
131
+ - **报告为什么看不到命中原文**:这是故意设计的脱敏纪律(「类」表述),防止报告本身变成可复制素材。
132
+ - **敏感读取检测能关吗**:不能——行为锚点②,数据隔离是防御默认,不提供关闭开关。
133
+ - **留痕在哪 / 怎么换位置**:默认 `~/.yotta-hardening/audit.log`;`--config-dir` 或 `$YOTTA_HARDENING_DIR` 覆盖。
134
+ - **命中一定是真问题吗**:静态扫描是启发式,命中需人工确认;置信度(0-100)供排优先级参考。
135
+ - **能扫别人的环境吗**:不能——只扫自有、有权检查的目录与配置。
136
+ - **法律红线**:本技能为防御 / 加固 / 教学用途,不产出可复制注入串、免杀、钓鱼、社工步骤;
137
+ 使用者自负合规责任(适用中国《网络安全法》《刑法》第 285 / 286 条红线)。
@@ -0,0 +1,434 @@
1
+ # -*- coding: utf-8 -*-
2
+ """hardening_rules.py — YottaMeta 元安全(yotta-agent-hardening)规则表。
3
+
4
+ 结构:
5
+ - TOOL_PATTERN_RULES:与 yotta-security-audit/scripts/audit_rules.py 的 PATTERN_RULES
6
+ 同步副本(勿手改;由 YottaSkills 仓库 tools/sync-hardening-rules.py 更新)。
7
+ - PIJ_PATTERN_RULES:与 yotta-verify/scripts/verify_rules.py 的 PIJ_PATTERN_RULES
8
+ 同步副本(勿手改;同上工具更新;元信该段为手工维护,单向同步到本文件)。
9
+ - HPI_PATTERN_RULES / HTO_PATTERN_RULES / HIS_PATTERN_RULES:元安全新增「配置面」维度规则,
10
+ 手工维护,不受同步影响。
11
+ - DOMAIN_OVERRIDE:把共享表里语义属于数据隔离 / 注入防护的规则归入对应域(元安全自身视图)。
12
+ - SKIP_RULES:环境级扫描中噪音大 / 价值低的规则(如纯文本 URL 提示)。
13
+ - RULE_SCOPE:规则只在特定文件类别上运行(scripts=脚本代码 / configs=配置面 / docs=文档)。
14
+
15
+ 规则撰写约束(防 ReDoS / 防误报 / 自扫不误报):
16
+ - 不使用嵌套量词(如 (a+)+);量词作用于字符类或固定串。
17
+ - 模式带「调用上下文」锚点,避免把规则表自身的字面量误报为命中。
18
+ - 单行输入在扫描前截断至 MAX_LINE_LEN。
19
+ - 描述一律「类」表述,不收录可复制注入串 / payload(双用途红线)。
20
+ """
21
+ import re
22
+ from collections import namedtuple
23
+
24
+ # 单条规则:规则号 / 检测器名 / 严重级 / 正则源码 / 描述 / 置信度(0-100)
25
+ Rule = namedtuple("Rule", ["id", "detector", "severity", "pattern", "description", "confidence"])
26
+
27
+ MAX_LINE_LEN = 500
28
+
29
+ # 严重级从低到高
30
+ SEVERITY_ORDER = ("info", "low", "medium", "high", "critical")
31
+ SEVERITY_VALUE = {"info": 0, "low": 0, "medium": 1, "high": 2, "critical": 3}
32
+
33
+ # 三域
34
+ DOMAINS = ("pi", "tools", "isolation")
35
+ DEFAULT_DOMAINS = DOMAINS
36
+
37
+ # 共享表规则归属覆盖(元安全自身视图,不受同步影响)
38
+ DOMAIN_OVERRIDE = {
39
+ # 数据隔离:凭据窃取 / 外传链
40
+ "CRE-001": "isolation", "CRE-002": "isolation", "CRE-003": "isolation",
41
+ "CRE-004": "isolation", "CRE-005": "isolation", "CRE-006": "isolation",
42
+ "CRE-007": "isolation",
43
+ "EXF-001": "isolation", "EXF-002": "isolation", "EXF-003": "isolation",
44
+ "EXF-004": "isolation", "EXF-005": "isolation",
45
+ # 注入防护:社工话术
46
+ "SOC-001": "pi", "SOC-002": "pi",
47
+ }
48
+
49
+ # 环境级扫描跳过(噪音大 / 价值低)
50
+ SKIP_RULES = {"NET-009"}
51
+
52
+ # 规则文件类别:scripts=脚本代码 / configs=配置面 / docs=文档(SKILL.md、references、模板)
53
+ SCOPE_SCRIPTS = "scripts"
54
+ SCOPE_CONFIGS = "configs"
55
+ SCOPE_DOCS = "docs"
56
+
57
+ # 规则作用域(不在其中的规则 = 全文本文件运行)
58
+ RULE_SCOPE = {
59
+ # 仅在脚本代码上运行(破坏性 / 自动确认 / 敏感输出)
60
+ "HTO-001": SCOPE_SCRIPTS, "HTO-001L": SCOPE_SCRIPTS, "HTO-002": SCOPE_SCRIPTS,
61
+ "HIS-003": SCOPE_SCRIPTS,
62
+ # 仅在配置面文件上运行(MCP / agent 配置 / .env 类)
63
+ "HTO-005": SCOPE_CONFIGS, "HTO-006": SCOPE_CONFIGS, "HTO-007": SCOPE_CONFIGS,
64
+ "HIS-004": SCOPE_CONFIGS,
65
+ # 文档 + 配置(权限 / 网络声明)
66
+ "HTO-003": SCOPE_DOCS, "HTO-004": SCOPE_DOCS,
67
+ }
68
+
69
+ # ══════════════════════════════════════════════════════════════════════════
70
+ # TOOL_PATTERN_RULES — 与元安 audit_rules.PATTERN_RULES 同步副本(勿手改;
71
+ # tools/sync-hardening-rules.py 更新;工具调用边界 + 数据流危险行为模式)
72
+ # ══════════════════════════════════════════════════════════════════════════
73
+ TOOL_PATTERN_RULES = [
74
+ # ── DownloadExec 下载即执行 ───────────────────────────────────────────
75
+ Rule("DEX-001", "DownloadExec", "critical",
76
+ r"(?i)\bcurl\b[^\n|;]{0,120}\|\s*(?:ba)?sh\b",
77
+ "curl 下载内容通过管道交给 shell 执行", 95),
78
+ Rule("DEX-002", "DownloadExec", "critical",
79
+ r"(?i)\bwget\b[^\n|;]{0,120}\|\s*(?:ba)?sh\b",
80
+ "wget 下载内容通过管道交给 shell 执行", 95),
81
+ Rule("DEX-003", "DownloadExec", "critical",
82
+ r"(?i)\bcurl\b[^\n|;&]{0,120}-[^\s]{0,20}o\s+\S+[^\n|;&]{0,80}(?:&&|;)\s*(?:ba)?sh\b",
83
+ "curl 下载到文件后立即交给 shell 执行", 90),
84
+ Rule("DEX-004", "DownloadExec", "critical",
85
+ r"(?i)\bfetch\s*\([^\n;]{0,200}\)\s*\.\s*then\s*\([^\n;]{0,80}\beval\b",
86
+ "JS fetch 结果交给 eval 执行", 85),
87
+ Rule("DEX-005", "DownloadExec", "critical",
88
+ r"(?i)\burllib\s*\.\s*request\s*\.\s*urlopen\s*\([^\n;]{0,200}\)[^\n;]{0,80}\bexec\b",
89
+ "Python urllib 下载结果交给 exec 执行", 85),
90
+ Rule("DEX-006", "DownloadExec", "critical",
91
+ r"(?i)\bwget\b[^\n|;&]{0,120}-[^\s]{0,20}o\s+\S+[^\n|;&]{0,80}(?:&&|;)\s*(?:ba)?sh\b",
92
+ "wget 下载到文件后立即交给 shell 执行", 90),
93
+ Rule("DEX-007", "DownloadExec", "critical",
94
+ r"(?i)\b(?:powershell|pwsh)\b[^\n;]{0,120}(?:-enc|enc(?:odedcommand)?)\b",
95
+ "PowerShell 编码命令执行", 80),
96
+
97
+ # ── Obfuscation 混淆执行 ──────────────────────────────────────────────
98
+ Rule("OBF-001", "Obfuscation", "high",
99
+ r"\beval\s*\(\s*[^\"'\x600-9]",
100
+ "eval 传入非字面量参数(可能执行外部输入)", 80),
101
+ Rule("OBF-002", "Obfuscation", "high",
102
+ r"(?<!\.)\bexec\s*\(\s*[^\"'\x600-9]",
103
+ "exec 传入非字面量参数", 80),
104
+ Rule("OBF-003", "Obfuscation", "high",
105
+ r"(?:\\x[0-9a-fA-F]{2}){6,}",
106
+ "连续十六进制转义序列(编码字符串)", 70),
107
+ Rule("OBF-004", "Obfuscation", "high",
108
+ r"chr\s*\(\s*\d+\s*\)\s*\+\s*chr\s*\(\s*\d+\s*\)(?:\s*\+\s*chr\s*\(\s*\d+\s*\)){2,}",
109
+ "chr() 拼接链(逐字符构造字符串)", 85),
110
+ Rule("OBF-005", "Obfuscation", "high",
111
+ r"String\s*\.\s*fromCharCode\s*\([^)]*,[^)]*,[^)]*,[^)]*\)",
112
+ "String.fromCharCode 多参数构造", 70),
113
+ Rule("OBF-006", "Obfuscation", "high",
114
+ r"\batob\s*\(\s*['\"][A-Za-z0-9+/=]{40,}['\"]\s*\)",
115
+ "atob 解码超长编码串", 65),
116
+ Rule("OBF-007", "Obfuscation", "high",
117
+ r"(?i)(?:(?:exec|eval|system)\s*\(\s*(?:base64\.)?b64decode\s*\(|(?:base64\.)?b64decode\s*\([^)]*\)\s*[^\n;]{0,60}\b(?:exec|eval|system)\b)",
118
+ "base64 解码后执行", 90),
119
+ Rule("OBF-008", "Obfuscation", "medium",
120
+ r"\[::\s*-1\s*\]",
121
+ "字符串反转切片(常见混淆手法,需结合上下文)", 40),
122
+
123
+ # ── Persistence 持久化 ────────────────────────────────────────────────
124
+ Rule("PER-001", "Persistence", "high",
125
+ r"(?i)\bcrontab\s+-(?:e|r)\b",
126
+ "修改 crontab(持久化)", 78),
127
+ Rule("PER-002", "Persistence", "high",
128
+ r"(?i)(?:>>|>)\s*[^\n;]{0,60}/etc/cron(?:\.d)?/",
129
+ "写入系统 crontab 目录", 80),
130
+ Rule("PER-003", "Persistence", "high",
131
+ r"(?i)\bcron\b[^\n;]{0,40}(?:@reboot|@daily|@hourly)",
132
+ "cron 定时任务(含重启执行)", 70),
133
+ Rule("PER-004", "Persistence", "high",
134
+ r"(?i)launchctl\s+(?:load|bootstrap|submit)",
135
+ "macOS launchctl 加载持久化任务", 80),
136
+ Rule("PER-005", "Persistence", "high",
137
+ r"(?i)(?:Library/(?:LaunchAgents|LaunchDaemons)|launchd\.plist|(?:>>|>)\s*[^\n;]{0,60}\.plist)",
138
+ "macOS 启动代理/守护(LaunchAgents/LaunchDaemons plist)持久化", 70),
139
+ Rule("PER-006", "Persistence", "high",
140
+ r"(?i)systemctl\s+(?:enable|start)\b",
141
+ "systemd 服务启用(持久化)", 60),
142
+ Rule("PER-007", "Persistence", "high",
143
+ r"(?i)(?:>>|>)\s*[^\n;]{0,80}/etc/systemd/system/",
144
+ "写入 systemd 服务文件", 75),
145
+ Rule("PER-008", "Persistence", "high",
146
+ r"(?i)(?:>>|>)\s*[^\n;]{0,80}/(?:etc/rc\.local|etc/rc\.d/)",
147
+ "写入 rc.local / rc.d 启动脚本", 80),
148
+ Rule("PER-009", "Persistence", "high",
149
+ r"(?i)(?:>>|>)\s*[^\n;]{0,80}\.(?:bashrc|zshrc|profile|bash_profile)\b",
150
+ "写入 shell 配置文件(持久化)", 78),
151
+ Rule("PER-010", "Persistence", "high",
152
+ r"(?i)HKEY_(?:CURRENT_USER|LOCAL_MACHINE)[^\n;]{0,80}(?:CurrentVersion\\)?Run(?:Once)?\b",
153
+ "Windows 注册表启动项", 80),
154
+ Rule("PER-011", "Persistence", "medium",
155
+ r"(?i)HKEY_[^\n;]{0,120}(?:AppInit_DLLs|UserInitMprLogonScript)",
156
+ "Windows 注册表全局持久化点(AppInit_DLLs/登录脚本)", 85),
157
+
158
+ # ── Exfiltration 数据外传 ─────────────────────────────────────────────
159
+ Rule("EXF-001", "Exfiltration", "high",
160
+ r"(?i)\b(?:zip|tar)\b[^\n;]{0,120}(?:-r\b|cf\b)[^\n;]{0,120}(?:\bcurl\b|\bwget\b|requests\.post|urllib)",
161
+ "打包后外传(zip/tar 压缩并上传)", 85),
162
+ Rule("EXF-002", "Exfiltration", "high",
163
+ r"(?i)(?:shutil\.make_archive|zipfile\.ZipFile)[^\n;]{0,120}[^\n;]{0,120}(?:requests\.post|urllib\.request|ftp)",
164
+ "Python 归档后上传", 85),
165
+ Rule("EXF-003", "Exfiltration", "high",
166
+ r"(?i)(?:\.env[^\n;]{0,80}(?:\bcurl\b|\bwget\b|requests\.post|urllib)|(?:\bcurl\b|\bwget\b|requests\.post|urllib)[^\n;]{0,80}\.env)",
167
+ "读取 .env 后外传", 88),
168
+ Rule("EXF-004", "Exfiltration", "high",
169
+ r"(?i)(?:(?:id_rsa|id_ed25519|\.ssh)[^\n;]{0,80}(?:\bcurl\b|\bwget\b|requests\.post|urllib|ftp)|(?:\bcurl\b|\bwget\b|requests\.post|urllib|ftp)[^\n;]{0,80}(?:id_rsa|id_ed25519|\.ssh))",
170
+ "读取 SSH 私钥后外传", 92),
171
+ Rule("EXF-005", "Exfiltration", "high",
172
+ r"(?i)(?:(?:Login\sData|Cookies\.sqlite|\.aws\\credentials)[^\n;]{0,80}(?:\bcurl\b|\bwget\b|requests\.post|urllib)|(?:\bcurl\b|\bwget\b|requests\.post|urllib)[^\n;]{0,80}(?:Login\sData|Cookies\.sqlite|\.aws\\credentials))",
173
+ "读取浏览器/云凭据后外传", 90),
174
+
175
+ # ── CredentialTheft 凭据窃取 ──────────────────────────────────────────
176
+ Rule("CRE-001", "CredentialTheft", "critical",
177
+ r"(?i)osascript[^\n;]{0,120}(?:password|passphrase)",
178
+ "macOS 弹窗套取密码", 90),
179
+ Rule("CRE-002", "CredentialTheft", "critical",
180
+ r"(?i)security\s+find-generic-password|keychain",
181
+ "访问 macOS keychain 凭据", 85),
182
+ Rule("CRE-003", "CredentialTheft", "high",
183
+ r"(?i)(?:id_rsa|id_ed25519|id_dsa)\.?(?:pub)?\b",
184
+ "读取 SSH 私钥文件", 80),
185
+ Rule("CRE-004", "CredentialTheft", "high",
186
+ r"(?i)\.aws[/\\](?:credentials|config)\b",
187
+ "读取 AWS 凭据文件", 85),
188
+ Rule("CRE-005", "CredentialTheft", "high",
189
+ r"(?i)(?:win32crypt|DPAPI|CryptUnprotectData)",
190
+ "Windows DPAPI 解密调用", 85),
191
+ Rule("CRE-006", "CredentialTheft", "medium",
192
+ r"(?i)\b(?:MEMORY\.md|USER\.md|SOUL\.md|IDENTITY\.md)\b",
193
+ "访问智能体记忆/身份文件(需确认必要性)", 60),
194
+ Rule("CRE-007", "CredentialTheft", "medium",
195
+ r"(?i)(?:cookie|session)[^\n;]{0,60}(?:steal|exfil|upload|post)",
196
+ "Cookie/会话窃取相关操作", 75),
197
+
198
+ # ── NetworkCall 网络调用(含反向 shell)───────────────────────────────
199
+ Rule("NET-001", "NetworkCall", "critical",
200
+ r"(?i)\bnc\s+[-A-Za-z0-9. ]{0,40}-e\b",
201
+ "netcat 反向 shell(-e 参数)", 95),
202
+ Rule("NET-002", "NetworkCall", "critical",
203
+ r"(?i)bash\s+-i\s*>\s*&?\s*/dev/tcp/",
204
+ "bash /dev/tcp 反向 shell", 95),
205
+ Rule("NET-003", "NetworkCall", "critical",
206
+ r"(?i)(?:socket|connect)\s*\([^\n;]{0,80}(?:receiver|attacker|hacker|remote)[^\n;]{0,40}\d{2,5}\)",
207
+ "连接疑似攻击者地址的 socket", 85),
208
+ Rule("NET-004", "NetworkCall", "medium",
209
+ r"(?i)\bsocket\s*\.\s*(?:socket|create_connection|connect)\b",
210
+ "原始 socket 连接(需确认目标)", 60),
211
+ Rule("NET-005", "NetworkCall", "medium",
212
+ r"(?i)requests\s*\.\s*(?:get|post|put|patch|delete|request)\s*\(",
213
+ "HTTP 客户端调用(需确认目标)", 40),
214
+ Rule("NET-006", "NetworkCall", "medium",
215
+ r"(?i)urllib\s*\.\s*request\b",
216
+ "urllib 网络调用(需确认目标)", 40),
217
+ Rule("NET-007", "NetworkCall", "medium",
218
+ r"(?i)\bfetch\s*\(\s*['\"]",
219
+ "JS fetch 网络调用(需确认目标)", 40),
220
+ Rule("NET-008", "NetworkCall", "medium",
221
+ r"(?i)\b(?:curl|wget|httpie|aria2c)\b\s+[-'\"A-Za-z0-9_.:/?=&%]",
222
+ "命令行下载工具调用(需确认目标)", 40),
223
+ Rule("NET-009", "NetworkCall", "low",
224
+ r"(?i)https?://",
225
+ "文本中出现 URL(需结合上下文)", 20),
226
+
227
+ # ── PrivilegeEscalation 权限提升 ──────────────────────────────────────
228
+ Rule("PRI-001", "PrivilegeEscalation", "high",
229
+ r"(?i)\bchmod\s+[0-7]*[267][0-7]{2}\b",
230
+ "chmod 设置 setuid/setgid/sticky 权限位", 85),
231
+ Rule("PRI-002", "PrivilegeEscalation", "high",
232
+ r"(?i)\bchmod\s+777\b",
233
+ "chmod 777 全权限", 70),
234
+ Rule("PRI-003", "PrivilegeEscalation", "high",
235
+ r"(?i)\bsetuid\s*\(|setgid\s*\(",
236
+ "调用 setuid/setgid", 80),
237
+ Rule("PRI-004", "PrivilegeEscalation", "medium",
238
+ r"(?i)usermod\s+-aG\s+(?:wheel|sudo|admin)\b|net\s+localgroup\s+administrators\s+\S+\s*/add",
239
+ "把用户加入管理员组", 85),
240
+ Rule("PRI-005", "PrivilegeEscalation", "low",
241
+ r"(?i)\bsudo\b",
242
+ "使用 sudo(需确认必要性)", 25),
243
+
244
+ # ── SocialEngineering 社会工程命名 ────────────────────────────────────
245
+ Rule("SOC-001", "SocialEngineering", "medium",
246
+ r"(?i)(?:airdrop|claim\s+reward|free\s+nft|verify\s+your\s+account|security\s+update\s+required|seed\s+phrase|2fa\s+bypass)",
247
+ "社会工程高频话术", 70),
248
+ Rule("SOC-002", "SocialEngineering", "medium",
249
+ r"(?i)(?:metamask|wallet|private\s+key\s+backup|助记词|钱包)",
250
+ "加密货币钱包相关命名", 55),
251
+ ]
252
+ # ══════════════════════════════════════════════════════════════════════════
253
+ # PIJ_PATTERN_RULES — 与元信 verify_rules.PIJ_PATTERN_RULES 同步副本(勿手改;tools/sync-hardening-rules.py 更新)
254
+ # ══════════════════════════════════════════════════════════════════════════
255
+ PIJ_PATTERN_RULES = [
256
+ # ── 指令覆盖 / 优先级操纵 ─────────────────────────────────────────────
257
+ Rule("PIJ-001", "PromptInjection", "high",
258
+ r"(?i)(?:ignore|disregard|forget|overlook|skip)\s+(?:all\s+|any\s+|the\s+|previous\s+)*(?:previous\s+|earlier\s+)*(?:instructions?|prompts?|directives?|guidelines?|rules?|context|messages?)",
259
+ "指令覆盖:要求忽略之前的指令/上下文(典型注入手法)", 85),
260
+ Rule("PIJ-002", "PromptInjection", "high",
261
+ r"(?i)(?:忽略|无视|忘记|不要理会|别管|忘掉)(?:之前|以上|前面|所有|一切)?(?:的)?(?:指令|提示|设定|规则|上下文|内容)",
262
+ "指令覆盖(中文):要求忽略之前指令/设定", 80),
263
+ Rule("PIJ-003", "PromptInjection", "high",
264
+ r"(?i)from\s+now\s+on[^\n]{0,40}(?:follow|obey|you\s+are|act)",
265
+ "从现在起重定向行为(长期覆盖)", 75),
266
+ Rule("PIJ-004", "PromptInjection", "high",
267
+ r"(?i)(?:override|disregard|bypass)\s+(?:all\s+)?(?:previous\s+)?(?:instructions?|rules?|safety|guardrails?|security)",
268
+ "覆盖/绕过安全护栏指令", 85),
269
+ # ── 角色伪造 / 权限升级 ──────────────────────────────────────────────
270
+ Rule("PIJ-005", "PromptInjection", "medium",
271
+ r"(?i)\byou\s+are\s+now\b[^\n]{0,60}(?:mode|role|system|admin|root|developer|assistant)",
272
+ "角色伪造:冒充系统/管理员/开发者角色", 70),
273
+ Rule("PIJ-006", "PromptInjection", "medium",
274
+ r"(?i)(?:act|behave|pretend)\s+as\s+(?:a\s+|an\s+)?(?:system|admin|root|god\s+mode|developer)",
275
+ "角色伪造:扮演系统/管理员(权限提升暗示)", 65),
276
+ Rule("PIJ-007", "PromptInjection", "medium",
277
+ r"(?i)(?:你现在是|从现在起你是|你的新角色是|从此刻起你是|你正在扮演)",
278
+ "角色伪造(中文):宣称新角色", 60),
279
+ Rule("PIJ-008", "PromptInjection", "medium",
280
+ r"(?i)with\s+(?:full|super|root|admin|system|unrestricted|unlimited)\s+(?:privileges|access|permissions?|power)",
281
+ "权限提升暗示:以全权/管理员权限执行", 70),
282
+ # ── 隐藏 / 编码指令 ──────────────────────────────────────────────────
283
+ Rule("PIJ-009", "PromptInjection", "high",
284
+ r"(?i)(?:以下内容|下面这段|注意).{0,30}(?:系统消息|系统指令|来自系统|这是系统)",
285
+ "伪系统消息:把注入内容伪装成系统指令", 75),
286
+ Rule("PIJ-010", "PromptInjection", "medium",
287
+ r"(?i)(?:decod(?:e|ing)|decode\s+this|解(?:码|密)).{0,40}(?:then|并|and)\s*(?:执行|run|follow|obey)",
288
+ "要求解码后执行(编码指令传递)", 70),
289
+ # ── 数据外传指令 ────────────────────────────────────────────────────
290
+ Rule("PIJ-011", "PromptInjection", "high",
291
+ r"(?i)(?:send|upload|post|exfiltrate|transmit)\s+(?:the|all|your|any)?\s*(?:contents?|data|files?|env\b|environment|keys?|secrets?|memory|context|conversation|prompts?)\s*(?:to|via|using)\s*(?:this\s+)?(?:url|endpoint|server|http)",
292
+ "数据外传指令:把上下文/密钥/记忆发送到外部地址", 85),
293
+ Rule("PIJ-012", "PromptInjection", "high",
294
+ r"(?i)(?:把|将|请将)(?:你的|所有|全部)?(?:上下文|记忆|环境变量|密钥|文件|对话|提示词).{0,40}(?:发送|上传|提交|传给|发给)",
295
+ "数据外传指令(中文)", 80),
296
+ Rule("PIJ-013", "PromptInjection", "high",
297
+ r"(?i)(?:read|open|load)\s+[^\n]{0,60}\.env\b[^\n]{0,80}(?:send|upload|post|exfil|传|发)",
298
+ "读取 .env 后外传", 88),
299
+ # ── 分隔符逃逸 / 伪系统标签 ──────────────────────────────────────────
300
+ Rule("PIJ-014", "PromptInjection", "medium",
301
+ r"(?i)(?:<|\[|\{)?\s*(?:system|sysadmin)\s*(?:message|prompt|instruction|role)?\s*(?:>|\]|\})",
302
+ "伪系统标签:使用 <system> 等标签伪装系统指令", 70),
303
+ Rule("PIJ-015", "PromptInjection", "high",
304
+ r"(?i)(?:reveal|show|print|output|display)\s+(?:me\s+|your\s+)?(?:system\s+)?(?:prompt|instructions?|system\s+message)",
305
+ "要求泄露系统提示词/内部指令", 70),
306
+ Rule("PIJ-016", "PromptInjection", "high",
307
+ r"(?i)(?:输出|显示|打印|告诉我).{0,20}(?:你的|系统)?(?:系统提示词|系统指令|内部指令)",
308
+ "要求泄露系统提示词(中文)", 70),
309
+ Rule("PIJ-017", "PromptInjection", "medium",
310
+ r"(?i)when\s+(?:i|the\s+user)\s+(?:say|type|send|input)\s+[^\n]{0,40}\s*(?:then|you\s+will|ignore|do)",
311
+ "条件触发注入:用户说特定词即执行", 65),
312
+ # ── 工具自执行指令 ───────────────────────────────────────────────────
313
+ Rule("PIJ-018", "PromptInjection", "high",
314
+ r"(?i)(?:run|execute|call)\s+(?:the\s+)?(?:following\s+)?(?:command|script|code)[^\n]{0,80}(?:curl|wget|powershell|bash\s+-c)",
315
+ "要求执行下载/命令工具", 75),
316
+ Rule("PIJ-019", "PromptInjection", "high",
317
+ r"(?i)(?:download|fetch|get)\s+[^\n]{0,60}(?:from\s+)?https?://[^\s]+[^\n]{0,60}(?:then|and)?\s*(?:run|execute|install)",
318
+ "下载后执行", 75),
319
+ Rule("PIJ-020", "PromptInjection", "high",
320
+ r"(?i)(?:执行|运行|下载并运行|安装).{0,40}(?:curl|wget|下载).{0,60}(?:然后|并)?(?:执行|运行)",
321
+ "要求执行下载/命令(中文)", 75),
322
+ # ── 越权 / 隐藏意图 ──────────────────────────────────────────────────
323
+ Rule("PIJ-021", "PromptInjection", "high",
324
+ r"(?i)(?:do\s+not|don'?t|never)\s+(?:tell|inform|notify|mention|reveal)\s+(?:the\s+)?user",
325
+ "隐藏意图:禁止告知用户", 85),
326
+ Rule("PIJ-022", "PromptInjection", "high",
327
+ r"(?i)(?:不要告诉用户|别告诉用户|无需告知用户|不用告诉用户|不要让用户知道)",
328
+ "隐藏意图(中文):禁止告知用户", 85),
329
+ Rule("PIJ-023", "PromptInjection", "high",
330
+ r"(?i)(?:reply|respond|answer)\s+(?:with|only)\s+(?:ok|yes|done|收到|好)",
331
+ "要求只回复确认词(掩盖真实行为)", 75),
332
+ Rule("PIJ-024", "PromptInjection", "high",
333
+ r"(?i)(?:只回复|仅回复|直接回复)\s*(?:OK|ok|收到|好|是)",
334
+ "要求只回复确认词(中文)", 70),
335
+ Rule("PIJ-025", "PromptInjection", "high",
336
+ r"(?i)(?:without|no\s+need\s+to)\s+(?:telling|informing|asking|consulting)\s+(?:the\s+)?user",
337
+ "要求不经用户同意直接执行", 80),
338
+ Rule("PIJ-026", "PromptInjection", "high",
339
+ r"(?i)(?:不要问用户|无需询问|不用问|不需要征求|别问用户)",
340
+ "要求不经用户同意直接执行(中文)", 80),
341
+ # ── 凭据 / 输入采集 ──────────────────────────────────────────────────
342
+ Rule("PIJ-027", "PromptInjection", "high",
343
+ r"(?i)(?:capture|record|log|monitor)\s+(?:all\s+)?(?:keystrokes|input|credentials?|passwords?|everything\s+the\s+user)",
344
+ "键盘/输入/凭据采集指令", 80),
345
+ Rule("PIJ-028", "PromptInjection", "high",
346
+ r"(?i)(?:记录|收集|监控|窃取)(?:用户)?(?:输入|键盘|密码|凭据|按键)",
347
+ "输入/凭据采集指令(中文)", 80),
348
+ ]
349
+ # ── HPI_PATTERN_RULES(元安全新增:配置面提示注入规则)
350
+ HPI_PATTERN_RULES = [
351
+ Rule("HPI-001", "CredentialPassThrough", "medium",
352
+ r"(?i)(?:(?:把|将|请|要求)|(?:pass|send|provide|give)(?=\s|[^\w]|[\u4e00-\u9fff]))"
353
+ r"[^\n]{0,24}(?:api[_-]?\s?key|access[_-]?\s?key|token|secret|密钥|凭据|密码|password|credential)"
354
+ r"[^\n]{0,24}(?:作为|当作|传给|传入|发送给|外发|透传|pass\b|as\b|to\b)",
355
+ "工具/技能描述要求把密钥、令牌、凭据作为参数传给工具或外部服务(凭据透传指令)", 75),
356
+ Rule("HPI-002", "PrivilegedInstall", "medium",
357
+ r"(?i)(?:(?:以)|(?:as|with)(?=\s|[^\w]))"
358
+ r"[^\n]{0,12}(?:管理员|root|SYSTEM|superuser|admin)"
359
+ r"[^\n]{0,24}(?:身份|权限|privileges?|permissions?|rights)"
360
+ r"[^\n]{0,28}(?:安装|覆盖|修改|替换|install|overwrite|replace|modify)",
361
+ "工具/技能描述要求以管理员或 SYSTEM 身份安装或覆盖系统配置(越权安装指令)", 70),
362
+ ]
363
+ HPI_B64_SUSPICIOUS_WORDS = (
364
+ "curl", "wget", "powershell", "cmd.exe", "/bin/sh", "/bin/bash",
365
+ "exec", "eval", "rm -rf", "http://", "https://", "base64", "download",
366
+ "下载", "执行", "运行", "注入",
367
+ )
368
+
369
+ # ── HTO_PATTERN_RULES(元安全新增:工具调用边界规则)──────────────────────
370
+ HTO_PATTERN_RULES = [
371
+ Rule("HTO-001", "DestructiveDelete", "high",
372
+ r"(?i)(?:rm\s+-rf\s+(?:/(?=\s|$)|/etc(?:\s|/|$)|/usr(?:\s|/|$)|/var(?:\s|/|$)"
373
+ r"|/home(?:\s|/|$)|/root(?:\s|/|$)|/boot(?:\s|/|$)|/dev(?:\s|/|$)|~|C:)"
374
+ r"|shutil\.rmtree\s*\(\s*['\"](?:/(?=['\"])|/etc|/usr|/var|/home|/root|/boot|/dev|C:|~)"
375
+ r"|Remove-Item\s+-Recurse[^\n]{0,40}C:\\)",
376
+ "破坏性删除指向系统或根路径(rm -rf /、递归删除系统目录等)", 90),
377
+ Rule("HTO-001L", "RecursiveDelete", "low",
378
+ r"(?i)(?:rm\s+-rf|shutil\.rmtree|os\.removedirs|Remove-Item\s+-Recurse|os\.remove\s*\(|os\.unlink\s*\()",
379
+ "脚本含删除/递归删除原语(需确认删除目标与必要性)", 60),
380
+ Rule("HTO-002", "AutoConfirmDestructive", "medium",
381
+ r"(?i)(?:yes\s*\||\b-y\b|--yes|--force|/y\b)[^\n]{0,80}(?:rm\s+-rf|shutil\.rmtree|Remove-Item\s+-Recurse|os\.removedirs)",
382
+ "破坏性命令带自动确认(-y/--force/yes|),无人工确认点", 75),
383
+ Rule("HTO-003", "BroadPermissionClaim", "medium",
384
+ r"(?i)(?:任意文件|所有文件|全部文件|任何文件|全盘|整个文件系统|读写系统目录|系统任意路径|任意路径|全局读写)"
385
+ r"|(?:(?:read|write|modify|access)\s+(?:any|all)\s+(?:file|files|directory|directories|path|system|data))",
386
+ "技能/工具声称可读写任意文件、系统目录或全盘(权限过宽声明)", 70),
387
+ Rule("HTO-004", "BroadNetworkClaim", "medium",
388
+ r"(?i)(?:任意外发|外发到任意|外传到任意|发送到任意|任意 URL|任意地址|任意目标)"
389
+ r"|(?:(?:send|upload|exfiltrate|transmit)\s+(?:data|file|content|anything)\s+(?:to\s+)?(?:anywhere|any|任意))",
390
+ "技能/工具声称可外发数据到任意地址(网络任意外发声明)", 70),
391
+
392
+ ]
393
+
394
+ # ── HIS_PATTERN_RULES(元安全新增:数据隔离规则)──────────────────────────
395
+ HIS_PATTERN_RULES = [
396
+ Rule("HIS-004", "HardcodedSecret", "medium",
397
+ r"(?i)(?<![\w-])(?:api[_-]?key|client_secret|access_key|secret|token|password|auth[_ -]?key)\s*\"?\s*[:=]\s*[\"']?"
398
+ r"(?!your|xxx|example|placeholder|CHANGE_ME|<)[A-Za-z0-9_\-./+]{12,}[\"']?",
399
+ "配置文件疑似硬编码凭据值(密钥/令牌/口令字面量,建议改用环境变量或凭据管理器)", 75),
400
+ ]
401
+
402
+ # ── MCP 配置面引擎正则(仅在解析到 mcpServers 的配置文件上运行;版本锁定用解析后 JSON 键判断)──────────
403
+ MCP_REMOTE_RE = re.compile(
404
+ r"(?i)https?://[^\s\"']+")
405
+ MCP_HIGH_PRIV_RE = re.compile(
406
+ r"(?i)(?:scope\s*\"?\s*[:=]\s*[\"']?\*|permissions?\s*\"?\s*[:=]\s*\[?\s*[\"']?\*"
407
+ r"|allow_all\s*\"?\s*[:=]\s*true|dangerous\s*\"?\s*[:=]\s*true|full[_ -]?access|unrestricted)")
408
+
409
+ # ── 引擎级正则(敏感读取 / 网络原语 / 敏感输出)──────────────────────────
410
+ # 高敏读取:SSH 私钥 / 云凭据 / 口令库
411
+ HIGH_SENS_READ_RE = re.compile(
412
+ r"(?i)(?:\.ssh[\\/]id_|\.aws[\\/]credentials|\.netrc|\.pgpass|id_rsa|id_ed25519|id_dsa"
413
+ r"|keych[ai]n|DPAP[I1]|win32crypt|credential_store|password_store)")
414
+ # 中敏读取:.env / cookie / token / 本地凭据文件
415
+ MED_SENS_READ_RE = re.compile(
416
+ r"(?i)(?:\.env\b|cookies?\.(?:json|txt)|tokens?\.(?:json|txt)|session\.(?:json|txt)"
417
+ r"|\.npmrc|\.gitconfig|credentials\.json|secrets?\.json)")
418
+ # 网络原语(跨上下文外传共现检测用)
419
+ NET_PRIMITIVE_RE = re.compile(
420
+ r"(?i)\b(?:urllib|requests|httpx|http\.client|socket|aiohttp|curl|wget|"
421
+ r"fetch\s*\(|axios|Invoke-WebRequest|xmlrpc|ftplib)")
422
+ # 读取上下文(敏感路径判定需与读取操作同现,避免把常量/签名数据当行为)
423
+ READ_CONTEXT_RE = re.compile(
424
+ r"(?i)(?:open\s*\(|read_text|read_bytes|readlines|read\s*\(|Path\s*\(|"
425
+ r"cat\b|Get-Content|type\b|load\s*\(|read_file|readfile|file_get_contents|"
426
+ r"IO\s*\.|File\s*\.Read|os\.path\.join|expanduser|resolve\s*\(|scandir|listdir|glob\s*\()")
427
+
428
+ # 敏感输出(打印/写日志敏感值)
429
+ SENS_OUTPUT_RE = re.compile(
430
+ r"(?i)(?:print|echo|logging\.|logger\.|console\.log|Write-Host|System\.Console\.Write)"
431
+ r"[^\n]{0,60}(?:api[_-]?key|token|secret|password|os\.environ\[|getenv\s*\(\s*['\"](?:api|token|secret|password))")
432
+
433
+ # 全部新增规则(HPI + HTO + HIS)供引擎统一注册
434
+ EXTRA_PATTERN_RULES = HPI_PATTERN_RULES + HTO_PATTERN_RULES + HIS_PATTERN_RULES