@kenhkl/agent-moss 0.9.0 → 0.9.1
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/dist/agents/__pycache__/__init__.cpython-312.pyc +0 -0
- package/dist/agents/__pycache__/base.cpython-312.pyc +0 -0
- package/dist/cli.js +605 -640
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.js +605 -640
- package/dist/engine/coordinator.js.map +1 -1
- package/dist/server.js +605 -640
- package/dist/server.js.map +1 -1
- package/dist/skills/intent_deviation_guard.md +1 -1
- package/dist/templates/security_judge_template.txt +1 -1
- package/package.json +1 -1
|
@@ -253,247 +253,6 @@ var init_agents = __esm({
|
|
|
253
253
|
}
|
|
254
254
|
});
|
|
255
255
|
|
|
256
|
-
// src/engine/heuristic.ts
|
|
257
|
-
function runHeuristicCheck(input) {
|
|
258
|
-
const command = `${input.aNext.actionType}: ${input.aNext.actionDetail}`;
|
|
259
|
-
const matched = [];
|
|
260
|
-
let highestSeverity = "low";
|
|
261
|
-
let highestRiskType = "";
|
|
262
|
-
const userRules = getCustomRules();
|
|
263
|
-
for (const rule of userRules) {
|
|
264
|
-
try {
|
|
265
|
-
const re = new RegExp(rule.pattern);
|
|
266
|
-
if (re.test(command)) {
|
|
267
|
-
if (rule.action === "Deny") {
|
|
268
|
-
matched.push(`\u81EA\u5B9A\u4E49\u89C4\u5219: ${rule.pattern}`);
|
|
269
|
-
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
270
|
-
highestSeverity = rule.severity;
|
|
271
|
-
highestRiskType = "custom_rule";
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
} catch {
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
let topRiskType = "";
|
|
279
|
-
for (const rule of DANGEROUS_PATTERNS) {
|
|
280
|
-
if (rule.pattern.test(command)) {
|
|
281
|
-
matched.push(rule.description);
|
|
282
|
-
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
283
|
-
highestSeverity = rule.severity;
|
|
284
|
-
topRiskType = rule.riskType;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
highestRiskType = topRiskType || highestRiskType;
|
|
289
|
-
const agentExt = getAgentExtensions(input.agentId);
|
|
290
|
-
if (agentExt?.extra_command_patterns) {
|
|
291
|
-
for (const rule of agentExt.extra_command_patterns) {
|
|
292
|
-
try {
|
|
293
|
-
const re = new RegExp(rule.pattern, "i");
|
|
294
|
-
if (re.test(command)) {
|
|
295
|
-
matched.push(`agent \u4E13\u5C5E\u89C4\u5219: ${rule.reason}`);
|
|
296
|
-
if (severityRank(rule.risk_level) > severityRank(highestSeverity)) {
|
|
297
|
-
highestSeverity = rule.risk_level;
|
|
298
|
-
highestRiskType = rule.risk_type;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
} catch {
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
const injectionText = `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
306
|
-
const injectionHits = checkInjectionKeywords(injectionText, agentExt?.extra_injection_keywords);
|
|
307
|
-
if (injectionHits.length > 0) {
|
|
308
|
-
const topHit = injectionHits.reduce((a, b) => severityRank(a.riskLevel) >= severityRank(b.riskLevel) ? a : b);
|
|
309
|
-
matched.push(...injectionHits.map((h) => `\u6CE8\u5165\u5173\u952E\u8BCD [${h.lang}]: ${h.keyword}`));
|
|
310
|
-
if (severityRank(topHit.riskLevel) > severityRank(highestSeverity)) {
|
|
311
|
-
highestSeverity = topHit.riskLevel;
|
|
312
|
-
highestRiskType = "prompt_injection";
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
if (matched.length > 0) {
|
|
316
|
-
return {
|
|
317
|
-
allowed: false,
|
|
318
|
-
reason: `\u68C0\u6D4B\u5230\u9AD8\u5371\u64CD\u4F5C: ${matched.join(", ")}`,
|
|
319
|
-
riskLevel: highestSeverity,
|
|
320
|
-
riskType: highestRiskType,
|
|
321
|
-
confidence: 95,
|
|
322
|
-
source: "heuristic",
|
|
323
|
-
violatedLayers: ["1.1"]
|
|
324
|
-
// 对齐 py coordinator.py:165(L1.1 = 命中高危命令模式/注入关键词)
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
return null;
|
|
328
|
-
}
|
|
329
|
-
function checkInjectionKeywords(text, extraKeywords) {
|
|
330
|
-
const hits = [];
|
|
331
|
-
for (const entry of INJECTION_KEYWORDS) {
|
|
332
|
-
if (text.includes(entry.keyword.toLowerCase())) {
|
|
333
|
-
hits.push(entry);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
if (extraKeywords) {
|
|
337
|
-
for (const entry of extraKeywords) {
|
|
338
|
-
if (text.includes(entry.keyword.toLowerCase())) {
|
|
339
|
-
hits.push({ keyword: entry.keyword, riskLevel: entry.risk_level, lang: entry.lang });
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return hits;
|
|
344
|
-
}
|
|
345
|
-
function isInlineScriptCommand(actionDetail) {
|
|
346
|
-
const re = /(?:^|\s)(?:python|python3|python3\.\d+|perl|perl5|ruby|jruby|mruby|node|php|lua)\s+(?:-[a-zA-Z]*[cer][a-zA-Z]*\s+)/i;
|
|
347
|
-
return re.test(actionDetail);
|
|
348
|
-
}
|
|
349
|
-
function severityRank(s) {
|
|
350
|
-
const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
351
|
-
return ranks[s] || 0;
|
|
352
|
-
}
|
|
353
|
-
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS;
|
|
354
|
-
var init_heuristic = __esm({
|
|
355
|
-
"src/engine/heuristic.ts"() {
|
|
356
|
-
"use strict";
|
|
357
|
-
init_esm_shims();
|
|
358
|
-
init_config();
|
|
359
|
-
init_agents();
|
|
360
|
-
INJECTION_KEYWORDS = [
|
|
361
|
-
// ---- Instruction Override ----
|
|
362
|
-
{ keyword: "ignore previous instructions", riskLevel: "critical", lang: "en" },
|
|
363
|
-
{ keyword: "ignore all previous", riskLevel: "critical", lang: "en" },
|
|
364
|
-
{ keyword: "disregard all prior", riskLevel: "critical", lang: "en" },
|
|
365
|
-
{ keyword: "forget everything", riskLevel: "high", lang: "en" },
|
|
366
|
-
{ keyword: "\u5FFD\u7565\u4E4B\u524D\u7684\u6307\u4EE4", riskLevel: "critical", lang: "zh" },
|
|
367
|
-
{ keyword: "\u5FFD\u7565\u6240\u6709\u5148\u524D\u7684", riskLevel: "critical", lang: "zh" },
|
|
368
|
-
{ keyword: "\u5FFD\u7565\u4E0A\u9762\u6240\u6709", riskLevel: "high", lang: "zh" },
|
|
369
|
-
{ keyword: "\u8BF7\u5FD8\u8BB0\u4E4B\u524D", riskLevel: "high", lang: "zh" },
|
|
370
|
-
// ---- Role Hijacking ----
|
|
371
|
-
{ keyword: "you are now", riskLevel: "high", lang: "en" },
|
|
372
|
-
{ keyword: "you are no longer", riskLevel: "high", lang: "en" },
|
|
373
|
-
{ keyword: "new instructions", riskLevel: "high", lang: "en" },
|
|
374
|
-
{ keyword: "from now on, you", riskLevel: "high", lang: "en" },
|
|
375
|
-
{ keyword: "\u4F60\u73B0\u5728\u662F\u4E00\u4E2A", riskLevel: "high", lang: "zh" },
|
|
376
|
-
{ keyword: "\u4F60\u4E0D\u518D\u662F\u4E00\u4E2A", riskLevel: "high", lang: "zh" },
|
|
377
|
-
{ keyword: "\u4ECE\u73B0\u5728\u5F00\u59CB\u4F60", riskLevel: "high", lang: "zh" },
|
|
378
|
-
{ keyword: "\u4F60\u7684\u65B0\u89D2\u8272\u662F", riskLevel: "high", lang: "zh" },
|
|
379
|
-
// ---- Command Injection ----
|
|
380
|
-
{ keyword: "system prompt", riskLevel: "high", lang: "en" },
|
|
381
|
-
{ keyword: "reveal your instructions", riskLevel: "high", lang: "en" },
|
|
382
|
-
{ keyword: "output your instructions", riskLevel: "high", lang: "en" },
|
|
383
|
-
{ keyword: "repeat your instructions", riskLevel: "medium", lang: "en" },
|
|
384
|
-
{ keyword: "\u7CFB\u7EDF\u63D0\u793A", riskLevel: "high", lang: "zh" },
|
|
385
|
-
{ keyword: "\u8F93\u51FA\u4F60\u7684\u6307\u4EE4", riskLevel: "high", lang: "zh" },
|
|
386
|
-
{ keyword: "\u91CD\u590D\u4F60\u7684\u6307\u4EE4", riskLevel: "medium", lang: "zh" },
|
|
387
|
-
// ---- Social Engineering ----
|
|
388
|
-
{ keyword: "this is an authorized test", riskLevel: "high", lang: "en" },
|
|
389
|
-
{ keyword: "security audit approved", riskLevel: "high", lang: "en" },
|
|
390
|
-
{ keyword: "admin override", riskLevel: "critical", lang: "en" },
|
|
391
|
-
{ keyword: "debug mode", riskLevel: "high", lang: "en" },
|
|
392
|
-
{ keyword: "maintenance mode", riskLevel: "high", lang: "en" },
|
|
393
|
-
{ keyword: "\u8FD9\u662F\u6388\u6743\u7684\u6D4B\u8BD5", riskLevel: "high", lang: "zh" },
|
|
394
|
-
{ keyword: "\u5B89\u5168\u5BA1\u8BA1\u5DF2\u6279\u51C6", riskLevel: "high", lang: "zh" },
|
|
395
|
-
{ keyword: "\u7BA1\u7406\u5458\u8986\u76D6", riskLevel: "critical", lang: "zh" },
|
|
396
|
-
{ keyword: "\u8C03\u8BD5\u6A21\u5F0F", riskLevel: "high", lang: "zh" },
|
|
397
|
-
// ---- XSS ----
|
|
398
|
-
{ keyword: "<script>", riskLevel: "high", lang: "en" },
|
|
399
|
-
{ keyword: "javascript:", riskLevel: "high", lang: "en" },
|
|
400
|
-
{ keyword: "onerror=", riskLevel: "high", lang: "en" },
|
|
401
|
-
{ keyword: "onload=", riskLevel: "high", lang: "en" },
|
|
402
|
-
// ---- Fake Boundaries ----
|
|
403
|
-
{ keyword: "=== END OF", riskLevel: "high", lang: "en" },
|
|
404
|
-
{ keyword: "--- END SYSTEM", riskLevel: "high", lang: "en" },
|
|
405
|
-
{ keyword: "[END OF", riskLevel: "high", lang: "en" },
|
|
406
|
-
{ keyword: "=== \u7ED3\u675F", riskLevel: "high", lang: "zh" },
|
|
407
|
-
{ keyword: "--- \u7ED3\u675F\u7CFB\u7EDF", riskLevel: "high", lang: "zh" },
|
|
408
|
-
// ---- Developer Mode ----
|
|
409
|
-
{ keyword: "developer mode", riskLevel: "critical", lang: "en" },
|
|
410
|
-
{ keyword: "DAN mode", riskLevel: "critical", lang: "en" },
|
|
411
|
-
{ keyword: "jailbreak", riskLevel: "critical", lang: "en" },
|
|
412
|
-
{ keyword: "\u5F00\u53D1\u8005\u6A21\u5F0F", riskLevel: "critical", lang: "zh" },
|
|
413
|
-
{ keyword: "\u8D8A\u72F1", riskLevel: "critical", lang: "zh" }
|
|
414
|
-
// 注:xiaoO 专属绕过词(绕过审计/禁用安全检查/关闭防护/bypass audit 等)
|
|
415
|
-
// 已迁至 agent_moss/agents/xiaoo/rules.json 的 extra_injection_keywords,
|
|
416
|
-
// 由 agent_ext 机制注入,不再污染通用层。
|
|
417
|
-
];
|
|
418
|
-
DANGEROUS_PATTERNS = [
|
|
419
|
-
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
420
|
-
// 1. rm -rf root dir (含通配符如 /* /.* 等) — 使用负向先行断言 (?!\w):/ 后面不是单词字符时匹配
|
|
421
|
-
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\/(?!\w)/i, severity: "critical", description: "\u9012\u5F52\u5F3A\u5236\u5220\u9664\u6839\u76EE\u5F55 (rm -rf /)", riskType: "script_execution" },
|
|
422
|
-
// 注意:已移除"rm -rf /任意绝对路径"的宽泛规则,避免误杀 /tmp 等临时目录清理操作
|
|
423
|
-
// 2. rm with -r or -f targeting system dirs
|
|
424
|
-
{ pattern: /\brm\s+-[a-zA-Z]*[rf][a-zA-Z]*\s+\/(etc|var|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55", riskType: "script_execution" },
|
|
425
|
-
// 3. rm -r absolute path (no -f)
|
|
426
|
-
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*\s+\//i, severity: "high", description: "\u9012\u5F52\u5220\u9664\u64CD\u4F5C (rm -r /...)", riskType: "script_execution" },
|
|
427
|
-
// 4. rm -f absolute path (no -r)
|
|
428
|
-
{ pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*\s+\//i, severity: "medium", description: "\u5F3A\u5236\u5220\u9664\u6587\u4EF6 (rm -f /...)", riskType: "script_execution" },
|
|
429
|
-
// dd 磁盘清零 — 只拦截写入系统关键目录,放行 /tmp 等临时目录
|
|
430
|
-
{ pattern: /dd\s+if=\/dev\/zero.*\bof\s*=\s*\/(etc|var|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u78C1\u76D8\u6E05\u96F6\u5199\u5165\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55 (dd if=/dev/zero of=/\u7CFB\u7EDF\u76EE\u5F55)", riskType: "script_execution" },
|
|
431
|
-
// mkfs 格式化 — 只拦截对块设备(/dev/sdX 等)的格式化,放行对普通文件的格式化
|
|
432
|
-
{ pattern: /mkfs\.\w+\s+\/dev\/(sd|hd|nvme|vd|loop|mapper|md|dm)\S+/i, severity: "critical", description: "\u683C\u5F0F\u5316\u5757\u8BBE\u5907 (mkfs /dev/\u5757\u8BBE\u5907)", riskType: "script_execution" },
|
|
433
|
-
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
434
|
-
// --- Critical: remote code execution ---
|
|
435
|
-
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
436
|
-
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
437
|
-
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
438
|
-
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "critical", description: "base64 \u89E3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
439
|
-
// --- Critical: reverse shell ---
|
|
440
|
-
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
441
|
-
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
442
|
-
// --- Critical: sensitive file access ---
|
|
443
|
-
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
444
|
-
{ pattern: /\/etc\/gshadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6 (/etc/gshadow)", riskType: "file_access" },
|
|
445
|
-
// 注意:/etc/passwd 已从拦截列表移除,因为它是公开可读的标准系统文件,真正敏感的是 /etc/shadow
|
|
446
|
-
{ pattern: /\.ssh\/id_rsa/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
447
|
-
// --- Critical: privilege escalation / container escape ---
|
|
448
|
-
{ pattern: /\/var\/run\/docker\.sock/i, severity: "critical", description: "\u8BBF\u95EE Docker socket\uFF0C\u53EF\u80FD\u5BFC\u81F4\u5BB9\u5668\u9003\u9038", riskType: "privilege_escalation" },
|
|
449
|
-
// --- High: dangerous permissions / ownership ---
|
|
450
|
-
{ pattern: /chmod\s+[0-7]*777[0-7]*/i, severity: "high", description: "\u5168\u6743\u9650\u8BBE\u7F6E (chmod 777)", riskType: "script_execution" },
|
|
451
|
-
{ pattern: /chown\s+root|chown\s+-R\s+\w+:\w+\s+\//i, severity: "high", description: "\u4FEE\u6539\u6240\u6709\u8005\u4E3A root / \u9012\u5F52\u4FEE\u6539\u6839\u76EE\u5F55\u6240\u6709\u8005", riskType: "script_execution" },
|
|
452
|
-
// sudo 提权 — 只拦截 sudo 后跟的危险命令,不一刀切拦截所有 sudo
|
|
453
|
-
{ pattern: /sudo\s+(rm|chmod|chown|dd|mkfs|format|iptables|crontab|passwd|userdel|useradd|groupdel)\b/i, severity: "high", description: "\u63D0\u6743\u6267\u884C\u9AD8\u5371\u547D\u4EE4 (sudo + \u5371\u9669\u64CD\u4F5C)", riskType: "privilege_escalation" },
|
|
454
|
-
// --- High: system config overwrite ---
|
|
455
|
-
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
456
|
-
// --- High: download script + execute risk ---
|
|
457
|
-
{ pattern: /(?:curl|wget)\s+.*(?:-o|--output|>)\s*\S+\.(?:sh|bash)\b/i, severity: "high", description: "\u8FDC\u7A0B\u4E0B\u8F7D\u811A\u672C\u5230\u672C\u5730", riskType: "script_execution" },
|
|
458
|
-
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
459
|
-
// --- High: package manager pipe-to-shell ---
|
|
460
|
-
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
461
|
-
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
462
|
-
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
463
|
-
// --- Medium: destructive git operations (降级为 medium,允许但记录) ---
|
|
464
|
-
{ pattern: /git\s+push\s+.*--force/i, severity: "medium", description: "\u5F3A\u5236\u63A8\u9001\u64CD\u4F5C (git push --force)\uFF0C\u53EF\u80FD\u8986\u76D6\u8FDC\u7A0B\u63D0\u4EA4\u5386\u53F2", riskType: "script_execution" },
|
|
465
|
-
// --- High: network port scanning (横向移动侦察) ---
|
|
466
|
-
{ pattern: /\bnmap\s+/i, severity: "high", description: "\u7F51\u7EDC\u7AEF\u53E3\u626B\u63CF (nmap)\uFF0C\u53EF\u80FD\u7528\u4E8E\u6A2A\u5411\u79FB\u52A8\u4FA6\u5BDF", riskType: "lateral_movement" },
|
|
467
|
-
{ pattern: /\b(masscan|zmap|unicornscan)\s+/i, severity: "high", description: "\u7F51\u7EDC\u7AEF\u53E3\u626B\u63CF\u5DE5\u5177\uFF0C\u53EF\u80FD\u7528\u4E8E\u6A2A\u5411\u79FB\u52A8\u4FA6\u5BDF", riskType: "lateral_movement" },
|
|
468
|
-
// --- Medium: credential export ---
|
|
469
|
-
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
470
|
-
// --- High: shell rc file append (persistence) ---
|
|
471
|
-
{ pattern: />>\s*(~|\/home\/[^/]+)\/(\.bashrc|\.zshrc|\.profile|\.bash_profile|\.zprofile)/, severity: "high", description: "\u68C0\u6D4B\u5230\u4FEE\u6539 Shell \u914D\u7F6E\u6587\u4EF6\uFF08~/.bashrc \u7B49\uFF09\uFF0C\u53EF\u80FD\u7528\u4E8E\u6301\u4E45\u5316\u540E\u95E8", riskType: "persistence" },
|
|
472
|
-
// --- High: device file write (只拦截重定向写入设备文件,不拦截读取) ---
|
|
473
|
-
{ pattern: />\s*\/dev\/(sd|hd|nvme|vd|loop|mem|kmsg|port|zero|random|urandom|full|core)/i, severity: "high", description: "\u91CD\u5B9A\u5411\u5199\u5165\u8BBE\u5907\u6587\u4EF6", riskType: "file_access" },
|
|
474
|
-
// --- High: non-interactive password modification ---
|
|
475
|
-
{ pattern: /\|\s*passwd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7BA1\u9053\u65B9\u5F0F\u8C03\u7528 passwd\uFF08\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\uFF09", riskType: "script_execution" },
|
|
476
|
-
{ pattern: /\bpasswd\s+--stdin\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 passwd --stdin \u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u8F93\u5165", riskType: "script_execution" },
|
|
477
|
-
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
478
|
-
{ pattern: /\b(newusers|lnewusers)\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 newusers/lnewusers \u6279\u91CF\u7528\u6237\u6DFB\u52A0\u547D\u4EE4", riskType: "script_execution" },
|
|
479
|
-
{ pattern: /\bpasswd\s+-[a-zA-Z]*d\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u5BC6\u7801\u64CD\u4F5C (passwd -d)", riskType: "script_execution" },
|
|
480
|
-
{ pattern: /\bpasswd\s+-[a-zA-Z]*l\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u9501\u5B9A\u7528\u6237\u8D26\u6237\u64CD\u4F5C (passwd -l)", riskType: "script_execution" },
|
|
481
|
-
// --- High: non-interactive password modification (extended) ---
|
|
482
|
-
{ pattern: /\blpasswd\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u64CD\u4F5C (lpasswd)", riskType: "script_execution" },
|
|
483
|
-
{ pattern: /\bgpasswd\s+(?!-[adA])/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7EC4\u5BC6\u7801\u7BA1\u7406\u64CD\u4F5C (gpasswd)", riskType: "script_execution" },
|
|
484
|
-
{ pattern: /\bchgpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u6279\u91CF\u4FEE\u6539\u7EC4\u5BC6\u7801\u64CD\u4F5C (chgpasswd)", riskType: "script_execution" },
|
|
485
|
-
// --- High: user/group deletion (irreversible, requires user consent) ---
|
|
486
|
-
{ pattern: /\buserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (userdel)", riskType: "script_execution" },
|
|
487
|
-
{ pattern: /\bdeluser\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (deluser)", riskType: "script_execution" },
|
|
488
|
-
{ pattern: /\bluserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (luserdel)", riskType: "script_execution" },
|
|
489
|
-
{ pattern: /\bgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (groupdel)", riskType: "script_execution" },
|
|
490
|
-
{ pattern: /\blgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (lgroupdel)", riskType: "script_execution" },
|
|
491
|
-
// --- High: generic command -p parameter password setting ---
|
|
492
|
-
{ pattern: /\b(useradd|luseradd|groupadd|usermod|lusermod|groupmod|lgroupmod)\b[^&|;]*?\s-p\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u901A\u8FC7 -p \u53C2\u6570\u8BBE\u7F6E\u6216\u4FEE\u6539\u5BC6\u7801 (useradd/usermod/groupmod)", riskType: "script_execution" }
|
|
493
|
-
];
|
|
494
|
-
}
|
|
495
|
-
});
|
|
496
|
-
|
|
497
256
|
// src/engine/inline-analyzer.ts
|
|
498
257
|
function isLiteralTextCommand(command) {
|
|
499
258
|
ECHO_CMD_RE.lastIndex = 0;
|
|
@@ -710,165 +469,26 @@ function runLogicCheck(input) {
|
|
|
710
469
|
}
|
|
711
470
|
}
|
|
712
471
|
}
|
|
713
|
-
if (!isExcludedType) {
|
|
714
|
-
const agentExt = getAgentExtensions(input.agentId || "");
|
|
715
|
-
const pathResult = checkSensitivePath(actionDetail, resolvedCwd, agentExt);
|
|
716
|
-
if (pathResult) return pathResult;
|
|
717
|
-
}
|
|
718
|
-
if (actionType !== "file_write" && actionType !== "file_edit") {
|
|
719
|
-
const TEMP_DIRS = ["/tmp/", "/var/tmp/", "/run/", "/dev/shm/"];
|
|
720
|
-
const isTempPath = TEMP_DIRS.some((td) => actionDetail.includes(td));
|
|
721
|
-
if (!isTempPath && (actionDetail.includes("*") || actionDetail.includes("?")) && ["rm ", "rm ", "del ", "del ", "delete", "remove ", "remove ", "\u5220\u9664", "\u79FB\u9664"].some((kw) => actionDetail.includes(kw))) {
|
|
722
|
-
return {
|
|
723
|
-
allowed: false,
|
|
724
|
-
reason: "\u68C0\u6D4B\u5230\u901A\u914D\u7B26\u7ED3\u5408\u5220\u9664\u64CD\u4F5C\uFF0C\u53EF\u80FD\u9020\u6210\u6279\u91CF\u8BEF\u5220",
|
|
725
|
-
riskLevel: "high",
|
|
726
|
-
riskType: "script_execution",
|
|
727
|
-
confidence: 90,
|
|
728
|
-
source: "logic_rule",
|
|
729
|
-
violatedLayers: ["2"]
|
|
730
|
-
};
|
|
731
|
-
}
|
|
732
|
-
if (/>\s*\/etc\//.test(actionDetail) || />\s*\/boot\//.test(actionDetail) || />\s*\/proc\//.test(actionDetail)) {
|
|
733
|
-
return {
|
|
734
|
-
allowed: false,
|
|
735
|
-
reason: "\u68C0\u6D4B\u5230\u91CD\u5B9A\u5411\u8986\u76D6\u5199\u5165\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55",
|
|
736
|
-
riskLevel: "critical",
|
|
737
|
-
riskType: "file_access",
|
|
738
|
-
confidence: 95,
|
|
739
|
-
source: "logic_rule",
|
|
740
|
-
violatedLayers: ["2"]
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
var _READ_ONLY_COMMANDS = /* @__PURE__ */ new Set([
|
|
745
|
-
"cat",
|
|
746
|
-
"head",
|
|
747
|
-
"tail",
|
|
748
|
-
"less",
|
|
749
|
-
"more",
|
|
750
|
-
"grep",
|
|
751
|
-
"find",
|
|
752
|
-
"awk",
|
|
753
|
-
"sed",
|
|
754
|
-
"sort",
|
|
755
|
-
"uniq",
|
|
756
|
-
"wc",
|
|
757
|
-
"cut",
|
|
758
|
-
"strings",
|
|
759
|
-
"od",
|
|
760
|
-
"xxd",
|
|
761
|
-
"hexdump",
|
|
762
|
-
"tr",
|
|
763
|
-
"file",
|
|
764
|
-
"stat",
|
|
765
|
-
"du",
|
|
766
|
-
"df",
|
|
767
|
-
"ls",
|
|
768
|
-
"dir",
|
|
769
|
-
"tree",
|
|
770
|
-
"nl",
|
|
771
|
-
"tac",
|
|
772
|
-
"rev",
|
|
773
|
-
"lsblk",
|
|
774
|
-
"blockdev",
|
|
775
|
-
"smartctl",
|
|
776
|
-
"udevadm",
|
|
777
|
-
"dmidecode",
|
|
778
|
-
"lscpu",
|
|
779
|
-
"lspci",
|
|
780
|
-
"lsusb",
|
|
781
|
-
"lsmem",
|
|
782
|
-
"lsns",
|
|
783
|
-
"lsof",
|
|
784
|
-
"hwinfo",
|
|
785
|
-
"inxi",
|
|
786
|
-
"fdisk",
|
|
787
|
-
"parted",
|
|
788
|
-
"dmesg",
|
|
789
|
-
"journalctl",
|
|
790
|
-
"systemctl",
|
|
791
|
-
"hostnamectl",
|
|
792
|
-
"localectl",
|
|
793
|
-
"timedatectl",
|
|
794
|
-
"ps",
|
|
795
|
-
"top",
|
|
796
|
-
"free",
|
|
797
|
-
"vmstat",
|
|
798
|
-
"iostat",
|
|
799
|
-
"mpstat",
|
|
800
|
-
"pidof",
|
|
801
|
-
"pgrep",
|
|
802
|
-
"ip",
|
|
803
|
-
"ifconfig",
|
|
804
|
-
"route",
|
|
805
|
-
"ss",
|
|
806
|
-
"netstat",
|
|
807
|
-
"arp",
|
|
808
|
-
"ethtool",
|
|
809
|
-
"nmcli",
|
|
810
|
-
"uname",
|
|
811
|
-
"arch",
|
|
812
|
-
"nproc",
|
|
813
|
-
"getconf",
|
|
814
|
-
"getent",
|
|
815
|
-
"id",
|
|
816
|
-
"whoami",
|
|
817
|
-
"who",
|
|
818
|
-
"w",
|
|
819
|
-
"last",
|
|
820
|
-
"uptime",
|
|
821
|
-
"lsmod",
|
|
822
|
-
"modinfo",
|
|
823
|
-
"sysctl"
|
|
824
|
-
]);
|
|
825
|
-
var _DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
|
|
826
|
-
var _WRITE_COMMAND_RES = [
|
|
827
|
-
/\brm\b/,
|
|
828
|
-
/\bunlink\b/,
|
|
829
|
-
/\brmdir\b/,
|
|
830
|
-
/\bshred\b/,
|
|
831
|
-
/\bcp\b/,
|
|
832
|
-
/\bmv\b/,
|
|
833
|
-
/\binstall\b/,
|
|
834
|
-
/\btee\b/,
|
|
835
|
-
/\bdd\b/,
|
|
836
|
-
/\bmkfs\b/,
|
|
837
|
-
/\b(fdisk|parted|cfdisk|sfdisk)\b/,
|
|
838
|
-
/\bchmod\b/,
|
|
839
|
-
/\bchown\b/,
|
|
840
|
-
/\btruncate\b/
|
|
841
|
-
];
|
|
842
472
|
const indirectResult = checkIndirectFileAccess(actionType, actionDetail, resolvedCwd);
|
|
843
473
|
if (indirectResult) return indirectResult;
|
|
844
474
|
if (actionDetail.includes("sudo") || actionDetail.includes("su -") || actionDetail.includes("chmod u+s") || actionDetail.includes("setuid")) {
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
)
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
if (targetHost && !isLocalHost(targetHost)) {
|
|
863
|
-
return {
|
|
864
|
-
allowed: false,
|
|
865
|
-
reason: `\u5C1D\u8BD5\u6A2A\u5411\u79FB\u52A8\u5230\u8FDC\u7A0B\u4E3B\u673A: ${targetHost}`,
|
|
866
|
-
riskLevel: "medium",
|
|
867
|
-
riskType: "lateral_movement",
|
|
868
|
-
confidence: 80,
|
|
869
|
-
source: "logic_rule",
|
|
870
|
-
violatedLayers: ["2"]
|
|
871
|
-
};
|
|
475
|
+
const detailAfterSudo = actionDetail.replace(/(^|\|\||&&|\s)sudo\s+/g, " ");
|
|
476
|
+
const isAdminCmd = ["apt", "systemctl", "yum", "dnf", "pacman", "zypper", "apk"].some((kw) => detailAfterSudo.includes(kw));
|
|
477
|
+
if (!isAdminCmd) {
|
|
478
|
+
const adminContext = actionHistory.some(
|
|
479
|
+
(h) => h.actionDetail.includes("sudo") || h.actionDetail.includes("apt") || h.actionDetail.includes("systemctl") || h.actionDetail.includes("yum") || h.actionDetail.includes("dnf") || h.actionDetail.includes("pacman") || h.actionDetail.includes("zypper") || h.actionDetail.includes("apk")
|
|
480
|
+
);
|
|
481
|
+
if (!adminContext) {
|
|
482
|
+
return {
|
|
483
|
+
allowed: false,
|
|
484
|
+
reason: "\u68C0\u6D4B\u5230\u63D0\u6743\u64CD\u4F5C\uFF0C\u672A\u53D1\u73B0\u5408\u6CD5\u7BA1\u7406\u4E0A\u4E0B\u6587",
|
|
485
|
+
riskLevel: "high",
|
|
486
|
+
riskType: "privilege_escalation",
|
|
487
|
+
confidence: 85,
|
|
488
|
+
source: "logic_rule",
|
|
489
|
+
violatedLayers: ["2"]
|
|
490
|
+
};
|
|
491
|
+
}
|
|
872
492
|
}
|
|
873
493
|
}
|
|
874
494
|
const pwdResult = checkPasswordConsent(actionType, actionDetail, actionHistory);
|
|
@@ -936,119 +556,6 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
|
|
|
936
556
|
}
|
|
937
557
|
return null;
|
|
938
558
|
}
|
|
939
|
-
function checkSensitivePath(command, cwd, agentExt) {
|
|
940
|
-
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
941
|
-
const _WRITE_CMD_RES = [/\brm\b/, /\bunlink\b/, /\brmdir\b/, /\bshred\b/, /\bcp\b/, /\bmv\b/, /\binstall\b/, /\btee\b/, /\bdd\b/, /\bmkfs\b/, /\b(fdisk|parted|cfdisk|sfdisk)\b/, /\bchmod\b/, /\bchown\b/, /\btruncate\b/];
|
|
942
|
-
const _DEVNULL_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
|
|
943
|
-
const _READONLY_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump", "tr", "file", "stat", "du", "df", "ls", "dir", "tree", "nl", "tac", "rev", "lsblk", "blockdev", "smartctl", "udevadm", "dmidecode", "lscpu", "lspci", "lsusb", "lsmem", "lsns", "lsof", "hwinfo", "inxi", "fdisk", "parted", "dmesg", "journalctl", "systemctl", "hostnamectl", "localectl", "timedatectl", "ps", "top", "free", "vmstat", "iostat", "mpstat", "pidof", "pgrep", "ip", "ifconfig", "route", "ss", "netstat", "arp", "ethtool", "nmcli", "uname", "arch", "nproc", "getconf", "getent", "id", "whoami", "who", "w", "last", "uptime", "lsmod", "modinfo", "sysctl"]);
|
|
944
|
-
const isWriteOpFlag = _WRITE_CMD_RES.some((rx) => rx.test(command)) || /\bsed\s+-[a-zA-Z]*i/.test(command) || command.includes(">") && !command.replace(_DEVNULL_RE, "").includes(">") || command.includes(">") && command.replace(_DEVNULL_RE, "").includes(">") && !_READONLY_CMDS.has(command.trim().split(/\s+/)[0]?.toLowerCase() || "") || WRITE_KEYWORDS.some((kw) => "".includes(kw) || command.includes(kw));
|
|
945
|
-
for (const sp of ROOT_SENSITIVE_PATHS) {
|
|
946
|
-
if (command.includes(sp.path.toLowerCase())) {
|
|
947
|
-
if (sp.path === "/dev/random") {
|
|
948
|
-
if (isWriteOpFlag) {
|
|
949
|
-
continue;
|
|
950
|
-
}
|
|
951
|
-
return {
|
|
952
|
-
allowed: false,
|
|
953
|
-
reason: `\u8BFB\u53D6\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
954
|
-
riskLevel: sp.riskLevel,
|
|
955
|
-
riskType: "sensitive_path_access",
|
|
956
|
-
confidence: 90,
|
|
957
|
-
source: "logic_rule",
|
|
958
|
-
violatedLayers: ["2"]
|
|
959
|
-
};
|
|
960
|
-
}
|
|
961
|
-
if (!isWriteOpFlag && !sp.credential) {
|
|
962
|
-
continue;
|
|
963
|
-
}
|
|
964
|
-
return {
|
|
965
|
-
allowed: false,
|
|
966
|
-
reason: `\u5C1D\u8BD5\u8BBF\u95EE\u7CFB\u7EDF\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
967
|
-
riskLevel: sp.riskLevel,
|
|
968
|
-
riskType: "sensitive_path_access",
|
|
969
|
-
confidence: 90,
|
|
970
|
-
source: "logic_rule",
|
|
971
|
-
violatedLayers: ["2"]
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
for (const sp of HOME_SENSITIVE_PATHS) {
|
|
976
|
-
const expanded = `${expandedCwd}/${sp.path}`;
|
|
977
|
-
if (command.includes(sp.path.toLowerCase()) || command.includes(expanded.toLowerCase())) {
|
|
978
|
-
if (!isWriteOpFlag && !sp.credential) {
|
|
979
|
-
continue;
|
|
980
|
-
}
|
|
981
|
-
return {
|
|
982
|
-
allowed: false,
|
|
983
|
-
reason: `\u5C1D\u8BD5\u8BBF\u95EE\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
984
|
-
riskLevel: sp.riskLevel,
|
|
985
|
-
riskType: "sensitive_path_access",
|
|
986
|
-
confidence: 90,
|
|
987
|
-
source: "logic_rule",
|
|
988
|
-
violatedLayers: ["2"]
|
|
989
|
-
};
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
if (agentExt?.extra_sensitive_paths && agentExt.extra_sensitive_paths.length > 0) {
|
|
993
|
-
for (const sp of agentExt.extra_sensitive_paths) {
|
|
994
|
-
const spPath = sp.path.toLowerCase();
|
|
995
|
-
const expanded = `${expandedCwd}/${spPath}`;
|
|
996
|
-
if (command.includes(spPath) || command.includes(expanded.toLowerCase())) {
|
|
997
|
-
const denyMode = sp.deny_mode || (sp.credential ? "deny_both" : sp.read_only ? "deny_read" : "deny_write");
|
|
998
|
-
if (denyMode === "deny_read") {
|
|
999
|
-
if (isWriteOpFlag) continue;
|
|
1000
|
-
} else if (denyMode === "deny_write") {
|
|
1001
|
-
if (!isWriteOpFlag) continue;
|
|
1002
|
-
}
|
|
1003
|
-
return {
|
|
1004
|
-
allowed: false,
|
|
1005
|
-
reason: `\u5C1D\u8BD5\u8BBF\u95EE agent \u4E13\u5C5E\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
1006
|
-
riskLevel: sp.risk_level,
|
|
1007
|
-
riskType: "sensitive_path_access",
|
|
1008
|
-
confidence: 90,
|
|
1009
|
-
source: "logic_rule",
|
|
1010
|
-
violatedLayers: ["2"]
|
|
1011
|
-
};
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
for (const cp of CREDENTIAL_PATHS) {
|
|
1016
|
-
const escaped = cp.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1017
|
-
const re = cp.path.startsWith(".") ? new RegExp(`(?:^|[\\s/\\\\'"])${escaped}\\b`) : new RegExp(`\\b${escaped}\\b`);
|
|
1018
|
-
if (re.test(command)) {
|
|
1019
|
-
return {
|
|
1020
|
-
allowed: false,
|
|
1021
|
-
reason: `\u8BBF\u95EE\u654F\u611F\u8DEF\u5F84: ${cp.desc} (${cp.path})`,
|
|
1022
|
-
riskLevel: cp.riskLevel,
|
|
1023
|
-
riskType: "sensitive_path_access",
|
|
1024
|
-
confidence: 90,
|
|
1025
|
-
source: "logic_rule",
|
|
1026
|
-
violatedLayers: ["2"],
|
|
1027
|
-
isCredential: true
|
|
1028
|
-
};
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
if ((command.includes("rm ") || command.includes("unlink")) && (command.includes("/etc/") || command.includes("/root/") || command.includes("/var/log/"))) {
|
|
1032
|
-
return {
|
|
1033
|
-
allowed: false,
|
|
1034
|
-
reason: "\u68C0\u6D4B\u5230\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55\u5185\u5BB9",
|
|
1035
|
-
riskLevel: "critical",
|
|
1036
|
-
riskType: "sensitive_path_access",
|
|
1037
|
-
confidence: 90,
|
|
1038
|
-
source: "logic_rule",
|
|
1039
|
-
violatedLayers: ["2"]
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
return null;
|
|
1043
|
-
}
|
|
1044
|
-
function extractRemoteHost(command) {
|
|
1045
|
-
const m = command.match(/(?:ssh|scp|rsync)\s+(?:-[\w]+\s+)*(\S+@\S+|\b(?!-)[\w.-]+\b)/);
|
|
1046
|
-
return m ? m[1] : null;
|
|
1047
|
-
}
|
|
1048
|
-
function isLocalHost(host) {
|
|
1049
|
-
const localNames = ["localhost", "127.0.0.1", "::1", process.env.HOSTNAME || "", "0.0.0.0"];
|
|
1050
|
-
return localNames.includes(host.replace(/.*@/, ""));
|
|
1051
|
-
}
|
|
1052
559
|
function checkPasswordConsent(actionType, actionDetail, actionHistory) {
|
|
1053
560
|
if (actionType !== "bash") return null;
|
|
1054
561
|
const isPasswordModify = PASSWORD_MODIFY_PATTERNS.some((p) => p.test(actionDetail));
|
|
@@ -1151,117 +658,533 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd) {
|
|
|
1151
658
|
}
|
|
1152
659
|
}
|
|
1153
660
|
}
|
|
1154
|
-
return null;
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
return {
|
|
664
|
+
allowed: false,
|
|
665
|
+
reason: "\u5185\u8054\u811A\u672C\u4F7F\u7528\u76EE\u5F55\u904D\u5386\u51FD\u6570\u52A8\u6001\u53D1\u73B0\u6587\u4EF6\u5E76\u6267\u884C\u8BFB\u5199\u64CD\u4F5C\uFF0C\u65E0\u6CD5\u83B7\u53D6 cwd \u5B9E\u9645\u6587\u4EF6\u5217\u8868\uFF0C\u8F6C\u5C423 LLM \u5206\u6790",
|
|
666
|
+
riskLevel: "medium",
|
|
667
|
+
riskType: "file_access",
|
|
668
|
+
confidence: 70,
|
|
669
|
+
source: "logic_rule",
|
|
670
|
+
violatedLayers: ["2"]
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
var ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, NON_WRITE_TOOLS, READ_ONLY_REDIR_CMDS, WRITE_KEYWORDS, READ_KEYWORDS, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW;
|
|
674
|
+
var init_logic_rules = __esm({
|
|
675
|
+
"src/engine/logic-rules.ts"() {
|
|
676
|
+
"use strict";
|
|
677
|
+
init_esm_shims();
|
|
678
|
+
init_inline_analyzer();
|
|
679
|
+
ROOT_SENSITIVE_PATHS = [
|
|
680
|
+
{ path: "/etc/shadow", riskLevel: "critical", desc: "\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6", credential: true },
|
|
681
|
+
{ path: "/etc/gshadow", riskLevel: "critical", desc: "\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6", credential: true },
|
|
682
|
+
// 注意:/etc/passwd 仅从 L1 启发式规则移除(公开可读),L2 敏感路径仍保留
|
|
683
|
+
{ path: "/etc/passwd", riskLevel: "high", desc: "\u7CFB\u7EDF\u7528\u6237\u6587\u4EF6" },
|
|
684
|
+
{ path: "/etc/sudoers", riskLevel: "critical", desc: "sudo \u914D\u7F6E", credential: true },
|
|
685
|
+
// 系统配置(仅拦截写入)
|
|
686
|
+
{ path: "/etc/hosts", riskLevel: "medium", desc: "DNS \u89E3\u6790\u914D\u7F6E" },
|
|
687
|
+
{ path: "/etc/crontab", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1" },
|
|
688
|
+
{ path: "/etc/cron.d/", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55\uFF08\u62C6\u5206\u5F0F crontab\uFF09" },
|
|
689
|
+
{ path: "/var/spool/cron/", riskLevel: "high", desc: "\u7528\u6237\u7EA7\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55" },
|
|
690
|
+
{ path: "/etc/systemd/", riskLevel: "high", desc: "systemd \u670D\u52A1\u914D\u7F6E" },
|
|
691
|
+
{ path: "/etc/ssh/sshd_config", riskLevel: "high", desc: "SSH \u670D\u52A1\u914D\u7F6E" },
|
|
692
|
+
{ path: "/etc/pam.d/", riskLevel: "high", desc: "PAM \u53EF\u63D2\u62D4\u8BA4\u8BC1\u6A21\u5757\u914D\u7F6E" },
|
|
693
|
+
// 危险目录(仅拦截写入)
|
|
694
|
+
{ path: "/boot/", riskLevel: "critical", desc: "\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55" },
|
|
695
|
+
{ path: "/proc/sys/", riskLevel: "high", desc: "\u5185\u6838\u53C2\u6570" },
|
|
696
|
+
{ path: "/sys/", riskLevel: "high", desc: "sysfs \u5185\u6838\u63A5\u53E3" },
|
|
697
|
+
// 设备文件(/dev/null、/dev/zero、/dev/urandom 已移除,误报率极高)
|
|
698
|
+
{ path: "/dev/random", riskLevel: "high", desc: "\u963B\u585E\u5F0F\u968F\u673A\u6570\u8BBE\u5907\uFF08\u8BFB\u53D6\u8017\u5C3D\u71B5\u6C60\uFF09" },
|
|
699
|
+
{ path: "/dev/mem", riskLevel: "critical", desc: "\u7269\u7406\u5185\u5B58\u8BBF\u95EE\u8BBE\u5907" },
|
|
700
|
+
{ path: "/dev/kmsg", riskLevel: "high", desc: "\u5185\u6838\u6D88\u606F\u7F13\u51B2\u533A" },
|
|
701
|
+
// SSH 主机私钥
|
|
702
|
+
{ path: "/etc/ssh/ssh_host_rsa_key", riskLevel: "critical", desc: "SSH \u4E3B\u673A RSA \u79C1\u94A5", credential: true },
|
|
703
|
+
{ path: "/etc/ssh/ssh_host_ed25519_key", riskLevel: "critical", desc: "SSH \u4E3B\u673A Ed25519 \u79C1\u94A5", credential: true },
|
|
704
|
+
{ path: "/etc/ssh/ssh_host_ecdsa_key", riskLevel: "critical", desc: "SSH \u4E3B\u673A ECDSA \u79C1\u94A5", credential: true }
|
|
705
|
+
];
|
|
706
|
+
HOME_SENSITIVE_PATHS = [
|
|
707
|
+
{ path: ".ssh/id_rsa", riskLevel: "critical", desc: "SSH \u79C1\u94A5", credential: true },
|
|
708
|
+
{ path: ".ssh/id_ed25519", riskLevel: "critical", desc: "SSH \u79C1\u94A5 (ed25519)", credential: true },
|
|
709
|
+
{ path: ".ssh/authorized_keys", riskLevel: "high", desc: "SSH \u6388\u6743\u5BC6\u94A5" },
|
|
710
|
+
// 持久化与命令劫持(仅拦截写入)
|
|
711
|
+
{ path: ".bashrc", riskLevel: "high", desc: "\u7528\u6237 Shell \u521D\u59CB\u5316\u811A\u672C" },
|
|
712
|
+
{ path: ".bash_profile", riskLevel: "high", desc: "\u7528\u6237 Shell \u767B\u5F55\u811A\u672C" },
|
|
713
|
+
{ path: ".profile", riskLevel: "high", desc: "\u7528\u6237\u901A\u7528\u767B\u5F55\u811A\u672C" },
|
|
714
|
+
{ path: ".aws/credentials", riskLevel: "critical", desc: "AWS \u51ED\u8BC1", credential: true },
|
|
715
|
+
{ path: ".gitconfig", riskLevel: "medium", desc: "Git \u914D\u7F6E" },
|
|
716
|
+
{ path: ".gnupg", riskLevel: "high", desc: "GPG \u5BC6\u94A5\u76EE\u5F55" }
|
|
717
|
+
];
|
|
718
|
+
CREDENTIAL_PATHS = [
|
|
719
|
+
{ path: "credentials.yml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
720
|
+
{ path: "credentials.yaml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
721
|
+
{ path: "secrets.yml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
722
|
+
{ path: "secrets.yaml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
723
|
+
{ path: ".env", riskLevel: "high", desc: "\u73AF\u5883\u53D8\u91CF/\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" }
|
|
724
|
+
];
|
|
725
|
+
NON_WRITE_TOOLS = /* @__PURE__ */ new Set(["ask_user_question", "glob", "grep", "list_dir", "count_text_length", "search"]);
|
|
726
|
+
READ_ONLY_REDIR_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump"]);
|
|
727
|
+
WRITE_KEYWORDS = ["write", "\u5199\u5165", "save", "\u4FDD\u5B58", "modify", "\u4FEE\u6539", "update", "\u66F4\u65B0", "delete", "\u5220\u9664", "remove", "\u79FB\u9664", "create", "\u521B\u5EFA", "append", "\u8FFD\u52A0", "truncate", "\u622A\u65AD", "overwrite", "\u8986\u76D6", "replace", "\u66FF\u6362"];
|
|
728
|
+
READ_KEYWORDS = ["read", "\u8BFB\u53D6", "cat", "head", "tail", "less", "more", "view", "\u67E5\u770B", "open", "\u6253\u5F00", "load", "\u52A0\u8F7D", "grep", "search", "\u641C\u7D22", "find", "\u67E5\u627E"];
|
|
729
|
+
CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
|
|
730
|
+
PASSWORD_MODIFY_PATTERNS = [
|
|
731
|
+
/\|\s*passwd\b/i,
|
|
732
|
+
/\bpasswd\s+--stdin\b/i,
|
|
733
|
+
/\bchpasswd\b/i,
|
|
734
|
+
/\bchgpasswd\b/i,
|
|
735
|
+
/\b(newusers|lnewusers)\b/i,
|
|
736
|
+
/\bpasswd\s+-[a-zA-Z]*d\b/i,
|
|
737
|
+
/\bpasswd\s+-[a-zA-Z]*l\b/i
|
|
738
|
+
];
|
|
739
|
+
USER_DELETION_PATTERNS = [
|
|
740
|
+
/\buserdel\s/i,
|
|
741
|
+
/\bdeluser\s/i,
|
|
742
|
+
/\bluserdel\s/i,
|
|
743
|
+
/\bgroupdel\s/i,
|
|
744
|
+
/\blgroupdel\s/i
|
|
745
|
+
];
|
|
746
|
+
INTENT_DEVIATION_PATTERNS = [
|
|
747
|
+
{
|
|
748
|
+
intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
|
|
749
|
+
dangerousActions: ["\u5220\u9664", "remove", "delete", "rm ", "\u683C\u5F0F\u5316", "format"],
|
|
750
|
+
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
intentKeywords: ["\u67E5\u8BE2", "\u641C\u7D22", "search", "query", "find"],
|
|
754
|
+
dangerousActions: ["\u4FEE\u6539", "update", "write", "\u5199\u5165", "alter"],
|
|
755
|
+
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u67E5\u8BE2/\u641C\u7D22\uFF0C\u4F46\u6267\u884C\u4E86\u4FEE\u6539\u64CD\u4F5C"
|
|
756
|
+
}
|
|
757
|
+
];
|
|
758
|
+
INLINE_SCRIPT_RE = /(?:^|\s)(?:python|python3|python3\.\d+|perl|perl5|ruby|jruby|mruby|node|php|lua)\s+(?:-[a-zA-Z]*[cer][a-zA-Z]*\s+)/i;
|
|
759
|
+
DIR_TRAVERSAL_KW = [
|
|
760
|
+
"os.listdir",
|
|
761
|
+
"os.walk",
|
|
762
|
+
"os.scandir",
|
|
763
|
+
"glob.glob",
|
|
764
|
+
"glob.iglob",
|
|
765
|
+
"pathlib.",
|
|
766
|
+
"iterdir",
|
|
767
|
+
"rglob",
|
|
768
|
+
"scandir(",
|
|
769
|
+
"listdir("
|
|
770
|
+
];
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// src/engine/heuristic.ts
|
|
775
|
+
function runHeuristicCheck(input) {
|
|
776
|
+
const command = `${input.aNext.actionType}: ${input.aNext.actionDetail}`;
|
|
777
|
+
const matched = [];
|
|
778
|
+
let highestSeverity = "low";
|
|
779
|
+
let highestRiskType = "";
|
|
780
|
+
const userRules = getCustomRules();
|
|
781
|
+
for (const rule of userRules) {
|
|
782
|
+
try {
|
|
783
|
+
const re = new RegExp(rule.pattern);
|
|
784
|
+
if (re.test(command)) {
|
|
785
|
+
if (rule.action === "Deny") {
|
|
786
|
+
matched.push(`\u81EA\u5B9A\u4E49\u89C4\u5219: ${rule.pattern}`);
|
|
787
|
+
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
788
|
+
highestSeverity = rule.severity;
|
|
789
|
+
highestRiskType = "custom_rule";
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
} catch {
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
let topRiskType = "";
|
|
797
|
+
for (const rule of DANGEROUS_PATTERNS) {
|
|
798
|
+
if (rule.pattern.test(command)) {
|
|
799
|
+
matched.push(rule.description);
|
|
800
|
+
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
801
|
+
highestSeverity = rule.severity;
|
|
802
|
+
topRiskType = rule.riskType;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
highestRiskType = topRiskType || highestRiskType;
|
|
807
|
+
const agentExt = getAgentExtensions(input.agentId);
|
|
808
|
+
if (agentExt?.extra_command_patterns) {
|
|
809
|
+
for (const rule of agentExt.extra_command_patterns) {
|
|
810
|
+
try {
|
|
811
|
+
const re = new RegExp(rule.pattern, "i");
|
|
812
|
+
if (re.test(command)) {
|
|
813
|
+
matched.push(`agent \u4E13\u5C5E\u89C4\u5219: ${rule.reason}`);
|
|
814
|
+
if (severityRank(rule.risk_level) > severityRank(highestSeverity)) {
|
|
815
|
+
highestSeverity = rule.risk_level;
|
|
816
|
+
highestRiskType = rule.risk_type;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
} catch {
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const injectionText = `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
824
|
+
const injectionHits = checkInjectionKeywords(injectionText, agentExt?.extra_injection_keywords);
|
|
825
|
+
if (injectionHits.length > 0) {
|
|
826
|
+
const topHit = injectionHits.reduce((a, b) => severityRank(a.riskLevel) >= severityRank(b.riskLevel) ? a : b);
|
|
827
|
+
matched.push(...injectionHits.map((h) => `\u6CE8\u5165\u5173\u952E\u8BCD [${h.lang}]: ${h.keyword}`));
|
|
828
|
+
if (severityRank(topHit.riskLevel) > severityRank(highestSeverity)) {
|
|
829
|
+
highestSeverity = topHit.riskLevel;
|
|
830
|
+
highestRiskType = "prompt_injection";
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
const actionTypeL = input.aNext.actionType.toLowerCase();
|
|
834
|
+
const detailL = input.aNext.actionDetail.toLowerCase();
|
|
835
|
+
const isExcludedType = SENSITIVE_EXCLUDED_PREFIXES.some((p) => actionTypeL.startsWith(p));
|
|
836
|
+
if (!isExcludedType) {
|
|
837
|
+
const pathResult = checkSensitivePath(detailL, input.cwd || "/", agentExt);
|
|
838
|
+
if (pathResult) return pathResult;
|
|
839
|
+
}
|
|
840
|
+
const dangerousResult = checkDangerousPatterns(actionTypeL, detailL);
|
|
841
|
+
if (dangerousResult) return dangerousResult;
|
|
842
|
+
const lateralResult = checkLateralMovement(detailL);
|
|
843
|
+
if (lateralResult) return lateralResult;
|
|
844
|
+
if (matched.length > 0) {
|
|
845
|
+
return {
|
|
846
|
+
allowed: false,
|
|
847
|
+
reason: `\u68C0\u6D4B\u5230\u9AD8\u5371\u64CD\u4F5C: ${matched.join(", ")}`,
|
|
848
|
+
riskLevel: highestSeverity,
|
|
849
|
+
riskType: highestRiskType,
|
|
850
|
+
confidence: 95,
|
|
851
|
+
source: "heuristic",
|
|
852
|
+
violatedLayers: ["1.1"]
|
|
853
|
+
// 对齐 py coordinator.py:165(L1.1 = 命中高危命令模式/注入关键词)
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
return null;
|
|
857
|
+
}
|
|
858
|
+
function checkInjectionKeywords(text, extraKeywords) {
|
|
859
|
+
const hits = [];
|
|
860
|
+
for (const entry of INJECTION_KEYWORDS) {
|
|
861
|
+
if (text.includes(entry.keyword.toLowerCase())) {
|
|
862
|
+
hits.push(entry);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
if (extraKeywords) {
|
|
866
|
+
for (const entry of extraKeywords) {
|
|
867
|
+
if (text.includes(entry.keyword.toLowerCase())) {
|
|
868
|
+
hits.push({ keyword: entry.keyword, riskLevel: entry.risk_level, lang: entry.lang });
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return hits;
|
|
873
|
+
}
|
|
874
|
+
function isInlineScriptCommand(actionDetail) {
|
|
875
|
+
const re = /(?:^|\s)(?:python|python3|python3\.\d+|perl|perl5|ruby|jruby|mruby|node|php|lua)\s+(?:-[a-zA-Z]*[cer][a-zA-Z]*\s+)/i;
|
|
876
|
+
return re.test(actionDetail);
|
|
877
|
+
}
|
|
878
|
+
function severityRank(s) {
|
|
879
|
+
const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
880
|
+
return ranks[s] || 0;
|
|
881
|
+
}
|
|
882
|
+
function checkSensitivePath(command, cwd, agentExt) {
|
|
883
|
+
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
884
|
+
const _WRITE_CMD_RES = [/\brm\b/, /\bunlink\b/, /\brmdir\b/, /\bshred\b/, /\bcp\b/, /\bmv\b/, /\binstall\b/, /\btee\b/, /\bdd\b/, /\bmkfs\b/, /\b(fdisk|parted|cfdisk|sfdisk)\b/, /\bchmod\b/, /\bchown\b/, /\btruncate\b/];
|
|
885
|
+
const _DEVNULL_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
|
|
886
|
+
const _READONLY_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump", "tr", "file", "stat", "du", "df", "ls", "dir", "tree", "nl", "tac", "rev", "lsblk", "blockdev", "smartctl", "udevadm", "dmidecode", "lscpu", "lspci", "lsusb", "lsmem", "lsns", "lsof", "hwinfo", "inxi", "fdisk", "parted", "dmesg", "journalctl", "systemctl", "hostnamectl", "localectl", "timedatectl", "ps", "top", "free", "vmstat", "iostat", "mpstat", "pidof", "pgrep", "ip", "ifconfig", "route", "ss", "netstat", "arp", "ethtool", "nmcli", "uname", "arch", "nproc", "getconf", "getent", "id", "whoami", "who", "w", "last", "uptime", "lsmod", "modinfo", "sysctl"]);
|
|
887
|
+
const isWriteOpFlag = _WRITE_CMD_RES.some((rx) => rx.test(command)) || /\bsed\s+-[a-zA-Z]*i/.test(command) || command.includes(">") && !command.replace(_DEVNULL_RE, "").includes(">") || command.includes(">") && command.replace(_DEVNULL_RE, "").includes(">") && !_READONLY_CMDS.has(command.trim().split(/\s+/)[0]?.toLowerCase() || "") || WRITE_KEYWORDS.some((kw) => "".includes(kw) || command.includes(kw));
|
|
888
|
+
for (const sp of ROOT_SENSITIVE_PATHS) {
|
|
889
|
+
if (command.includes(sp.path.toLowerCase())) {
|
|
890
|
+
if (sp.path === "/dev/random") {
|
|
891
|
+
if (isWriteOpFlag) {
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
return {
|
|
895
|
+
allowed: false,
|
|
896
|
+
reason: `\u8BFB\u53D6\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
897
|
+
riskLevel: sp.riskLevel,
|
|
898
|
+
riskType: "file_access",
|
|
899
|
+
confidence: 90,
|
|
900
|
+
source: "heuristic",
|
|
901
|
+
violatedLayers: ["1.1"]
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
if (!isWriteOpFlag && !sp.credential) {
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
return {
|
|
908
|
+
allowed: false,
|
|
909
|
+
reason: `\u5C1D\u8BD5\u8BBF\u95EE\u7CFB\u7EDF\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
910
|
+
riskLevel: sp.riskLevel,
|
|
911
|
+
riskType: "file_access",
|
|
912
|
+
confidence: 90,
|
|
913
|
+
source: "heuristic",
|
|
914
|
+
violatedLayers: ["1.1"],
|
|
915
|
+
isCredential: !!sp.credential
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
for (const sp of HOME_SENSITIVE_PATHS) {
|
|
920
|
+
const expanded = `${expandedCwd}/${sp.path}`;
|
|
921
|
+
const pathRe = sp.path.endsWith(".pub") ? new RegExp(sp.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i") : new RegExp(sp.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "(?!\\.pub)", "i");
|
|
922
|
+
const expandedRe = sp.path.endsWith(".pub") ? new RegExp(expanded.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i") : new RegExp(expanded.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "(?!\\.pub)", "i");
|
|
923
|
+
if (pathRe.test(command) || expandedRe.test(command)) {
|
|
924
|
+
if (!isWriteOpFlag && !sp.credential) {
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
return {
|
|
928
|
+
allowed: false,
|
|
929
|
+
reason: `\u5C1D\u8BD5\u8BBF\u95EE\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
930
|
+
riskLevel: sp.riskLevel,
|
|
931
|
+
riskType: "file_access",
|
|
932
|
+
confidence: 90,
|
|
933
|
+
source: "heuristic",
|
|
934
|
+
violatedLayers: ["1.1"],
|
|
935
|
+
isCredential: !!sp.credential
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (agentExt?.extra_sensitive_paths && agentExt.extra_sensitive_paths.length > 0) {
|
|
940
|
+
for (const sp of agentExt.extra_sensitive_paths) {
|
|
941
|
+
const spPath = sp.path.toLowerCase();
|
|
942
|
+
const expanded = `${expandedCwd}/${spPath}`;
|
|
943
|
+
if (command.includes(spPath) || command.includes(expanded.toLowerCase())) {
|
|
944
|
+
const denyMode = sp.deny_mode || (sp.credential ? "deny_both" : sp.read_only ? "deny_read" : "deny_write");
|
|
945
|
+
if (denyMode === "deny_read") {
|
|
946
|
+
if (isWriteOpFlag) continue;
|
|
947
|
+
} else if (denyMode === "deny_write") {
|
|
948
|
+
if (!isWriteOpFlag) continue;
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
951
|
+
allowed: false,
|
|
952
|
+
reason: `\u5C1D\u8BD5\u8BBF\u95EE agent \u4E13\u5C5E\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
953
|
+
riskLevel: sp.risk_level,
|
|
954
|
+
riskType: "file_access",
|
|
955
|
+
confidence: 90,
|
|
956
|
+
source: "heuristic",
|
|
957
|
+
violatedLayers: ["1.1"],
|
|
958
|
+
isCredential: !!sp.credential
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
for (const cp of CREDENTIAL_PATHS) {
|
|
964
|
+
const escaped = cp.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
965
|
+
const re = cp.path.startsWith(".") ? new RegExp(`(?:^|[\\s/\\\\'"])${escaped}\\b`) : new RegExp(`\\b${escaped}\\b`);
|
|
966
|
+
if (re.test(command)) {
|
|
967
|
+
return {
|
|
968
|
+
allowed: false,
|
|
969
|
+
reason: `\u8BBF\u95EE\u654F\u611F\u8DEF\u5F84: ${cp.desc} (${cp.path})`,
|
|
970
|
+
riskLevel: cp.riskLevel,
|
|
971
|
+
riskType: "file_access",
|
|
972
|
+
confidence: 90,
|
|
973
|
+
source: "heuristic",
|
|
974
|
+
violatedLayers: ["1.1"],
|
|
975
|
+
isCredential: true
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
if ((command.includes("rm ") || command.includes("unlink")) && (command.includes("/etc/") || command.includes("/root/") || command.includes("/var/log/"))) {
|
|
980
|
+
return {
|
|
981
|
+
allowed: false,
|
|
982
|
+
reason: "\u68C0\u6D4B\u5230\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55\u5185\u5BB9",
|
|
983
|
+
riskLevel: "critical",
|
|
984
|
+
riskType: "file_access",
|
|
985
|
+
confidence: 90,
|
|
986
|
+
source: "heuristic",
|
|
987
|
+
violatedLayers: ["1.1"]
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
function checkDangerousPatterns(actionType, actionDetail) {
|
|
993
|
+
if (actionType === "file_write" || actionType === "file_edit") return null;
|
|
994
|
+
const TEMP_DIRS = ["/tmp/", "/var/tmp/", "/run/", "/dev/shm/"];
|
|
995
|
+
const isTempPath = TEMP_DIRS.some((td) => actionDetail.includes(td));
|
|
996
|
+
if (!isTempPath && (actionDetail.includes("*") || actionDetail.includes("?")) && ["rm ", "rm ", "del ", "del ", "delete", "remove ", "remove ", "\u5220\u9664", "\u79FB\u9664"].some((kw) => actionDetail.includes(kw))) {
|
|
997
|
+
return {
|
|
998
|
+
allowed: false,
|
|
999
|
+
reason: "\u68C0\u6D4B\u5230\u901A\u914D\u7B26\u7ED3\u5408\u5220\u9664\u64CD\u4F5C\uFF0C\u53EF\u80FD\u9020\u6210\u6279\u91CF\u8BEF\u5220",
|
|
1000
|
+
riskLevel: "high",
|
|
1001
|
+
riskType: "script_execution",
|
|
1002
|
+
confidence: 90,
|
|
1003
|
+
source: "heuristic",
|
|
1004
|
+
violatedLayers: ["1.1"]
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
if (/>\s*\/etc\//.test(actionDetail) || />\s*\/boot\//.test(actionDetail) || />\s*\/proc\//.test(actionDetail)) {
|
|
1008
|
+
return {
|
|
1009
|
+
allowed: false,
|
|
1010
|
+
reason: "\u68C0\u6D4B\u5230\u91CD\u5B9A\u5411\u8986\u76D6\u5199\u5165\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55",
|
|
1011
|
+
riskLevel: "critical",
|
|
1012
|
+
riskType: "file_access",
|
|
1013
|
+
confidence: 95,
|
|
1014
|
+
source: "heuristic",
|
|
1015
|
+
violatedLayers: ["1.1"]
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
return null;
|
|
1019
|
+
}
|
|
1020
|
+
function extractRemoteHost(command) {
|
|
1021
|
+
const m = command.match(/(?:ssh|scp|rsync)\s+(?:-[\w]+\s+)*(\S+@\S+|\b(?!-)[\w.-]+\b)/);
|
|
1022
|
+
return m ? m[1] : null;
|
|
1023
|
+
}
|
|
1024
|
+
function isLocalHost(host) {
|
|
1025
|
+
const localNames = ["localhost", "127.0.0.1", "::1", process.env.HOSTNAME || "", "0.0.0.0"];
|
|
1026
|
+
return localNames.includes(host.replace(/.*@/, ""));
|
|
1027
|
+
}
|
|
1028
|
+
function checkLateralMovement(actionDetail) {
|
|
1029
|
+
if (/(?:ssh|scp|rsync)\s+/.test(actionDetail)) {
|
|
1030
|
+
const targetHost = extractRemoteHost(actionDetail);
|
|
1031
|
+
if (targetHost && !isLocalHost(targetHost)) {
|
|
1032
|
+
return {
|
|
1033
|
+
allowed: false,
|
|
1034
|
+
reason: `\u5C1D\u8BD5\u6A2A\u5411\u79FB\u52A8\u5230\u8FDC\u7A0B\u4E3B\u673A: ${targetHost}`,
|
|
1035
|
+
riskLevel: "medium",
|
|
1036
|
+
riskType: "lateral_movement",
|
|
1037
|
+
confidence: 80,
|
|
1038
|
+
source: "heuristic",
|
|
1039
|
+
violatedLayers: ["1.1"]
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1155
1042
|
}
|
|
1156
|
-
return
|
|
1157
|
-
allowed: false,
|
|
1158
|
-
reason: "\u5185\u8054\u811A\u672C\u4F7F\u7528\u76EE\u5F55\u904D\u5386\u51FD\u6570\u52A8\u6001\u53D1\u73B0\u6587\u4EF6\u5E76\u6267\u884C\u8BFB\u5199\u64CD\u4F5C\uFF0C\u65E0\u6CD5\u83B7\u53D6 cwd \u5B9E\u9645\u6587\u4EF6\u5217\u8868\uFF0C\u8F6C\u5C423 LLM \u5206\u6790",
|
|
1159
|
-
riskLevel: "medium",
|
|
1160
|
-
riskType: "file_access",
|
|
1161
|
-
confidence: 70,
|
|
1162
|
-
source: "logic_rule",
|
|
1163
|
-
violatedLayers: ["2"]
|
|
1164
|
-
};
|
|
1043
|
+
return null;
|
|
1165
1044
|
}
|
|
1166
|
-
var
|
|
1167
|
-
var
|
|
1168
|
-
"src/engine/
|
|
1045
|
+
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES;
|
|
1046
|
+
var init_heuristic = __esm({
|
|
1047
|
+
"src/engine/heuristic.ts"() {
|
|
1169
1048
|
"use strict";
|
|
1170
1049
|
init_esm_shims();
|
|
1171
|
-
|
|
1050
|
+
init_config();
|
|
1172
1051
|
init_agents();
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
{
|
|
1178
|
-
{
|
|
1179
|
-
|
|
1180
|
-
{
|
|
1181
|
-
{
|
|
1182
|
-
{
|
|
1183
|
-
{
|
|
1184
|
-
|
|
1185
|
-
{
|
|
1186
|
-
{
|
|
1187
|
-
|
|
1188
|
-
{
|
|
1189
|
-
{
|
|
1190
|
-
{
|
|
1191
|
-
|
|
1192
|
-
{
|
|
1193
|
-
|
|
1194
|
-
{
|
|
1195
|
-
|
|
1196
|
-
{
|
|
1197
|
-
{
|
|
1198
|
-
{
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
{
|
|
1203
|
-
{
|
|
1204
|
-
|
|
1205
|
-
{
|
|
1206
|
-
{
|
|
1207
|
-
{
|
|
1208
|
-
{
|
|
1209
|
-
{
|
|
1210
|
-
{
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
{
|
|
1214
|
-
{
|
|
1215
|
-
{
|
|
1216
|
-
|
|
1217
|
-
{
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
/\bpasswd\s+-[a-zA-Z]*l\b/i
|
|
1232
|
-
];
|
|
1233
|
-
USER_DELETION_PATTERNS = [
|
|
1234
|
-
/\buserdel\s/i,
|
|
1235
|
-
/\bdeluser\s/i,
|
|
1236
|
-
/\bluserdel\s/i,
|
|
1237
|
-
/\bgroupdel\s/i,
|
|
1238
|
-
/\blgroupdel\s/i
|
|
1239
|
-
];
|
|
1240
|
-
INTENT_DEVIATION_PATTERNS = [
|
|
1241
|
-
{
|
|
1242
|
-
intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
|
|
1243
|
-
dangerousActions: ["\u5220\u9664", "remove", "delete", "rm ", "\u683C\u5F0F\u5316", "format"],
|
|
1244
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
|
|
1245
|
-
},
|
|
1246
|
-
{
|
|
1247
|
-
intentKeywords: ["\u67E5\u8BE2", "\u641C\u7D22", "search", "query", "find"],
|
|
1248
|
-
dangerousActions: ["\u4FEE\u6539", "update", "write", "\u5199\u5165", "alter"],
|
|
1249
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u67E5\u8BE2/\u641C\u7D22\uFF0C\u4F46\u6267\u884C\u4E86\u4FEE\u6539\u64CD\u4F5C"
|
|
1250
|
-
}
|
|
1052
|
+
init_logic_rules();
|
|
1053
|
+
INJECTION_KEYWORDS = [
|
|
1054
|
+
// ---- Instruction Override ----
|
|
1055
|
+
{ keyword: "ignore previous instructions", riskLevel: "critical", lang: "en" },
|
|
1056
|
+
{ keyword: "ignore all previous", riskLevel: "critical", lang: "en" },
|
|
1057
|
+
{ keyword: "disregard all prior", riskLevel: "critical", lang: "en" },
|
|
1058
|
+
{ keyword: "forget everything", riskLevel: "high", lang: "en" },
|
|
1059
|
+
{ keyword: "\u5FFD\u7565\u4E4B\u524D\u7684\u6307\u4EE4", riskLevel: "critical", lang: "zh" },
|
|
1060
|
+
{ keyword: "\u5FFD\u7565\u6240\u6709\u5148\u524D\u7684", riskLevel: "critical", lang: "zh" },
|
|
1061
|
+
{ keyword: "\u5FFD\u7565\u4E0A\u9762\u6240\u6709", riskLevel: "high", lang: "zh" },
|
|
1062
|
+
{ keyword: "\u8BF7\u5FD8\u8BB0\u4E4B\u524D", riskLevel: "high", lang: "zh" },
|
|
1063
|
+
// ---- Role Hijacking ----
|
|
1064
|
+
{ keyword: "you are now", riskLevel: "high", lang: "en" },
|
|
1065
|
+
{ keyword: "you are no longer", riskLevel: "high", lang: "en" },
|
|
1066
|
+
{ keyword: "new instructions", riskLevel: "high", lang: "en" },
|
|
1067
|
+
{ keyword: "from now on, you", riskLevel: "high", lang: "en" },
|
|
1068
|
+
{ keyword: "\u4F60\u73B0\u5728\u662F\u4E00\u4E2A", riskLevel: "high", lang: "zh" },
|
|
1069
|
+
{ keyword: "\u4F60\u4E0D\u518D\u662F\u4E00\u4E2A", riskLevel: "high", lang: "zh" },
|
|
1070
|
+
{ keyword: "\u4ECE\u73B0\u5728\u5F00\u59CB\u4F60", riskLevel: "high", lang: "zh" },
|
|
1071
|
+
{ keyword: "\u4F60\u7684\u65B0\u89D2\u8272\u662F", riskLevel: "high", lang: "zh" },
|
|
1072
|
+
// ---- Command Injection ----
|
|
1073
|
+
{ keyword: "system prompt", riskLevel: "high", lang: "en" },
|
|
1074
|
+
{ keyword: "reveal your instructions", riskLevel: "high", lang: "en" },
|
|
1075
|
+
{ keyword: "output your instructions", riskLevel: "high", lang: "en" },
|
|
1076
|
+
{ keyword: "repeat your instructions", riskLevel: "medium", lang: "en" },
|
|
1077
|
+
{ keyword: "\u7CFB\u7EDF\u63D0\u793A", riskLevel: "high", lang: "zh" },
|
|
1078
|
+
{ keyword: "\u8F93\u51FA\u4F60\u7684\u6307\u4EE4", riskLevel: "high", lang: "zh" },
|
|
1079
|
+
{ keyword: "\u91CD\u590D\u4F60\u7684\u6307\u4EE4", riskLevel: "medium", lang: "zh" },
|
|
1080
|
+
// ---- Social Engineering ----
|
|
1081
|
+
{ keyword: "this is an authorized test", riskLevel: "high", lang: "en" },
|
|
1082
|
+
{ keyword: "security audit approved", riskLevel: "high", lang: "en" },
|
|
1083
|
+
{ keyword: "admin override", riskLevel: "critical", lang: "en" },
|
|
1084
|
+
{ keyword: "debug mode", riskLevel: "high", lang: "en" },
|
|
1085
|
+
{ keyword: "maintenance mode", riskLevel: "high", lang: "en" },
|
|
1086
|
+
{ keyword: "\u8FD9\u662F\u6388\u6743\u7684\u6D4B\u8BD5", riskLevel: "high", lang: "zh" },
|
|
1087
|
+
{ keyword: "\u5B89\u5168\u5BA1\u8BA1\u5DF2\u6279\u51C6", riskLevel: "high", lang: "zh" },
|
|
1088
|
+
{ keyword: "\u7BA1\u7406\u5458\u8986\u76D6", riskLevel: "critical", lang: "zh" },
|
|
1089
|
+
{ keyword: "\u8C03\u8BD5\u6A21\u5F0F", riskLevel: "high", lang: "zh" },
|
|
1090
|
+
// ---- XSS ----
|
|
1091
|
+
{ keyword: "<script>", riskLevel: "high", lang: "en" },
|
|
1092
|
+
{ keyword: "javascript:", riskLevel: "high", lang: "en" },
|
|
1093
|
+
{ keyword: "onerror=", riskLevel: "high", lang: "en" },
|
|
1094
|
+
{ keyword: "onload=", riskLevel: "high", lang: "en" },
|
|
1095
|
+
// ---- Fake Boundaries ----
|
|
1096
|
+
{ keyword: "=== END OF", riskLevel: "high", lang: "en" },
|
|
1097
|
+
{ keyword: "--- END SYSTEM", riskLevel: "high", lang: "en" },
|
|
1098
|
+
{ keyword: "[END OF", riskLevel: "high", lang: "en" },
|
|
1099
|
+
{ keyword: "=== \u7ED3\u675F", riskLevel: "high", lang: "zh" },
|
|
1100
|
+
{ keyword: "--- \u7ED3\u675F\u7CFB\u7EDF", riskLevel: "high", lang: "zh" },
|
|
1101
|
+
// ---- Developer Mode ----
|
|
1102
|
+
{ keyword: "developer mode", riskLevel: "critical", lang: "en" },
|
|
1103
|
+
{ keyword: "DAN mode", riskLevel: "critical", lang: "en" },
|
|
1104
|
+
{ keyword: "jailbreak", riskLevel: "critical", lang: "en" },
|
|
1105
|
+
{ keyword: "\u5F00\u53D1\u8005\u6A21\u5F0F", riskLevel: "critical", lang: "zh" },
|
|
1106
|
+
{ keyword: "\u8D8A\u72F1", riskLevel: "critical", lang: "zh" }
|
|
1107
|
+
// 注:xiaoO 专属绕过词(绕过审计/禁用安全检查/关闭防护/bypass audit 等)
|
|
1108
|
+
// 已迁至 agent_moss/agents/xiaoo/rules.json 的 extra_injection_keywords,
|
|
1109
|
+
// 由 agent_ext 机制注入,不再污染通用层。
|
|
1251
1110
|
];
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
"
|
|
1256
|
-
"
|
|
1257
|
-
|
|
1258
|
-
"
|
|
1259
|
-
|
|
1260
|
-
"
|
|
1261
|
-
|
|
1262
|
-
"
|
|
1263
|
-
|
|
1111
|
+
DANGEROUS_PATTERNS = [
|
|
1112
|
+
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
1113
|
+
// 1. rm -rf root dir (含通配符如 /* /.* 等) — 使用负向先行断言 (?!\w):/ 后面不是单词字符时匹配
|
|
1114
|
+
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\/(?!\w)/i, severity: "critical", description: "\u9012\u5F52\u5F3A\u5236\u5220\u9664\u6839\u76EE\u5F55 (rm -rf /)", riskType: "script_execution" },
|
|
1115
|
+
// 注意:已移除"rm -rf /任意绝对路径"的宽泛规则,避免误杀 /tmp 等临时目录清理操作
|
|
1116
|
+
// 2. rm with -r or -f targeting system dirs — var 分支排除 /var/tmp/(合法清理)
|
|
1117
|
+
{ pattern: /\brm\s+-[a-zA-Z]*[rf][a-zA-Z]*\s+\/(etc|var(?!\/tmp)|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55", riskType: "script_execution" },
|
|
1118
|
+
// 3. rm -r absolute path (no -f) — 排除 /tmp/ /var/tmp/ /run/ /dev/shm/(CI/开发高频合法清理)
|
|
1119
|
+
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*\s+\/(?!tmp\/|var\/tmp\/|run\/|dev\/shm\/)/i, severity: "high", description: "\u9012\u5F52\u5220\u9664\u64CD\u4F5C (rm -r /...)", riskType: "script_execution" },
|
|
1120
|
+
// 4. rm -f absolute path (no -r) — 同样排除临时目录
|
|
1121
|
+
{ pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*\s+\/(?!tmp\/|var\/tmp\/|run\/|dev\/shm\/)/i, severity: "medium", description: "\u5F3A\u5236\u5220\u9664\u6587\u4EF6 (rm -f /...)", riskType: "script_execution" },
|
|
1122
|
+
// dd 磁盘清零 — 只拦截写入系统关键目录,放行 /tmp 等临时目录
|
|
1123
|
+
{ pattern: /dd\s+if=\/dev\/zero.*\bof\s*=\s*\/(etc|var|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u78C1\u76D8\u6E05\u96F6\u5199\u5165\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55 (dd if=/dev/zero of=/\u7CFB\u7EDF\u76EE\u5F55)", riskType: "script_execution" },
|
|
1124
|
+
// mkfs 格式化 — 只拦截对块设备(/dev/sdX 等)的格式化,放行对普通文件的格式化
|
|
1125
|
+
{ pattern: /mkfs\.\w+\s+\/dev\/(sd|hd|nvme|vd|loop|mapper|md|dm)\S+/i, severity: "critical", description: "\u683C\u5F0F\u5316\u5757\u8BBE\u5907 (mkfs /dev/\u5757\u8BBE\u5907)", riskType: "script_execution" },
|
|
1126
|
+
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
1127
|
+
// --- Critical: remote code execution ---
|
|
1128
|
+
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
1129
|
+
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
1130
|
+
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
1131
|
+
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "critical", description: "base64 \u89E3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
1132
|
+
// --- Critical: reverse shell ---
|
|
1133
|
+
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
1134
|
+
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
1135
|
+
// --- Critical: sensitive file access ---
|
|
1136
|
+
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
1137
|
+
{ pattern: /\/etc\/gshadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6 (/etc/gshadow)", riskType: "file_access" },
|
|
1138
|
+
// 注意:/etc/passwd 已从拦截列表移除,因为它是公开可读的标准系统文件,真正敏感的是 /etc/shadow
|
|
1139
|
+
{ pattern: /\.ssh\/id_rsa(?!\.pub)/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
1140
|
+
// --- Critical: privilege escalation / container escape ---
|
|
1141
|
+
{ pattern: /\/var\/run\/docker\.sock/i, severity: "critical", description: "\u8BBF\u95EE Docker socket\uFF0C\u53EF\u80FD\u5BFC\u81F4\u5BB9\u5668\u9003\u9038", riskType: "privilege_escalation" },
|
|
1142
|
+
// --- High: dangerous permissions / ownership ---
|
|
1143
|
+
{ pattern: /chmod\s+[0-7]*777[0-7]*/i, severity: "high", description: "\u5168\u6743\u9650\u8BBE\u7F6E (chmod 777)", riskType: "script_execution" },
|
|
1144
|
+
{ pattern: /chown\s+root|chown\s+-R\s+\w+:\w+\s+\//i, severity: "high", description: "\u4FEE\u6539\u6240\u6709\u8005\u4E3A root / \u9012\u5F52\u4FEE\u6539\u6839\u76EE\u5F55\u6240\u6709\u8005", riskType: "script_execution" },
|
|
1145
|
+
// sudo 提权 — 只拦截 sudo 后跟的危险命令,不一刀切拦截所有 sudo
|
|
1146
|
+
{ pattern: /sudo\s+(rm|chmod|chown|dd|mkfs|format|iptables|crontab|passwd|userdel|useradd|groupdel)\b/i, severity: "high", description: "\u63D0\u6743\u6267\u884C\u9AD8\u5371\u547D\u4EE4 (sudo + \u5371\u9669\u64CD\u4F5C)", riskType: "privilege_escalation" },
|
|
1147
|
+
// --- High: system config overwrite ---
|
|
1148
|
+
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
1149
|
+
// --- High: download script + execute risk ---
|
|
1150
|
+
{ pattern: /(?:curl|wget)\s+.*(?:-o|--output|>)\s*\S+\.(?:sh|bash)\b/i, severity: "high", description: "\u8FDC\u7A0B\u4E0B\u8F7D\u811A\u672C\u5230\u672C\u5730", riskType: "script_execution" },
|
|
1151
|
+
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
1152
|
+
// --- High: package manager pipe-to-shell ---
|
|
1153
|
+
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
1154
|
+
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
1155
|
+
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
1156
|
+
// --- Medium: destructive git operations (降级为 medium,允许但记录) ---
|
|
1157
|
+
{ pattern: /git\s+push\s+.*--force/i, severity: "medium", description: "\u5F3A\u5236\u63A8\u9001\u64CD\u4F5C (git push --force)\uFF0C\u53EF\u80FD\u8986\u76D6\u8FDC\u7A0B\u63D0\u4EA4\u5386\u53F2", riskType: "script_execution" },
|
|
1158
|
+
// --- High: network port scanning (横向移动侦察) ---
|
|
1159
|
+
{ pattern: /\bnmap\s+/i, severity: "high", description: "\u7F51\u7EDC\u7AEF\u53E3\u626B\u63CF (nmap)\uFF0C\u53EF\u80FD\u7528\u4E8E\u6A2A\u5411\u79FB\u52A8\u4FA6\u5BDF", riskType: "lateral_movement" },
|
|
1160
|
+
{ pattern: /\b(masscan|zmap|unicornscan)\s+/i, severity: "high", description: "\u7F51\u7EDC\u7AEF\u53E3\u626B\u63CF\u5DE5\u5177\uFF0C\u53EF\u80FD\u7528\u4E8E\u6A2A\u5411\u79FB\u52A8\u4FA6\u5BDF", riskType: "lateral_movement" },
|
|
1161
|
+
// --- Medium: credential export ---
|
|
1162
|
+
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
1163
|
+
// --- High: shell rc file append (persistence) ---
|
|
1164
|
+
{ pattern: />>\s*(~|\/home\/[^/]+)\/(\.bashrc|\.zshrc|\.profile|\.bash_profile|\.zprofile)/, severity: "high", description: "\u68C0\u6D4B\u5230\u4FEE\u6539 Shell \u914D\u7F6E\u6587\u4EF6\uFF08~/.bashrc \u7B49\uFF09\uFF0C\u53EF\u80FD\u7528\u4E8E\u6301\u4E45\u5316\u540E\u95E8", riskType: "persistence" },
|
|
1165
|
+
// --- High: device file write (只拦截重定向写入设备文件,不拦截读取) ---
|
|
1166
|
+
{ pattern: />\s*\/dev\/(sd|hd|nvme|vd|loop|mem|kmsg|port|zero|random|urandom|full|core)/i, severity: "high", description: "\u91CD\u5B9A\u5411\u5199\u5165\u8BBE\u5907\u6587\u4EF6", riskType: "file_access" },
|
|
1167
|
+
// --- High: non-interactive password modification ---
|
|
1168
|
+
{ pattern: /\|\s*passwd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7BA1\u9053\u65B9\u5F0F\u8C03\u7528 passwd\uFF08\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\uFF09", riskType: "script_execution" },
|
|
1169
|
+
{ pattern: /\bpasswd\s+--stdin\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 passwd --stdin \u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u8F93\u5165", riskType: "script_execution" },
|
|
1170
|
+
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
1171
|
+
{ pattern: /\b(newusers|lnewusers)\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 newusers/lnewusers \u6279\u91CF\u7528\u6237\u6DFB\u52A0\u547D\u4EE4", riskType: "script_execution" },
|
|
1172
|
+
{ pattern: /\bpasswd\s+-[a-zA-Z]*d\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u5BC6\u7801\u64CD\u4F5C (passwd -d)", riskType: "script_execution" },
|
|
1173
|
+
{ pattern: /\bpasswd\s+-[a-zA-Z]*l\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u9501\u5B9A\u7528\u6237\u8D26\u6237\u64CD\u4F5C (passwd -l)", riskType: "script_execution" },
|
|
1174
|
+
// --- High: non-interactive password modification (extended) ---
|
|
1175
|
+
{ pattern: /\blpasswd\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u64CD\u4F5C (lpasswd)", riskType: "script_execution" },
|
|
1176
|
+
{ pattern: /\bgpasswd\s+(?!-[adA])/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7EC4\u5BC6\u7801\u7BA1\u7406\u64CD\u4F5C (gpasswd)", riskType: "script_execution" },
|
|
1177
|
+
{ pattern: /\bchgpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u6279\u91CF\u4FEE\u6539\u7EC4\u5BC6\u7801\u64CD\u4F5C (chgpasswd)", riskType: "script_execution" },
|
|
1178
|
+
// --- High: user/group deletion (irreversible, requires user consent) ---
|
|
1179
|
+
{ pattern: /\buserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (userdel)", riskType: "script_execution" },
|
|
1180
|
+
{ pattern: /\bdeluser\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (deluser)", riskType: "script_execution" },
|
|
1181
|
+
{ pattern: /\bluserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (luserdel)", riskType: "script_execution" },
|
|
1182
|
+
{ pattern: /\bgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (groupdel)", riskType: "script_execution" },
|
|
1183
|
+
{ pattern: /\blgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (lgroupdel)", riskType: "script_execution" },
|
|
1184
|
+
// --- High: generic command -p parameter password setting ---
|
|
1185
|
+
{ pattern: /\b(useradd|luseradd|groupadd|usermod|lusermod|groupmod|lgroupmod)\b[^&|;]*?\s-p\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u901A\u8FC7 -p \u53C2\u6570\u8BBE\u7F6E\u6216\u4FEE\u6539\u5BC6\u7801 (useradd/usermod/groupmod)", riskType: "script_execution" }
|
|
1264
1186
|
];
|
|
1187
|
+
SENSITIVE_EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
1265
1188
|
}
|
|
1266
1189
|
});
|
|
1267
1190
|
|
|
@@ -1664,7 +1587,10 @@ function getEnabledL1CommandPatterns(runtime) {
|
|
|
1664
1587
|
}));
|
|
1665
1588
|
}
|
|
1666
1589
|
function getEnabledL2SensitivePaths(runtime) {
|
|
1667
|
-
|
|
1590
|
+
let cat = runtime.L1_rules?.sensitive_path_access;
|
|
1591
|
+
if (!cat || !cat.rules || cat.rules.length === 0) {
|
|
1592
|
+
cat = runtime.L2_rules?.sensitive_path_access || { category_enabled: true, rules: [] };
|
|
1593
|
+
}
|
|
1668
1594
|
return filterEnabledRules(cat.rules || [], cat.category_enabled).map((r) => {
|
|
1669
1595
|
const out = { path: r.path || "", risk_level: r.risk_level || "", desc: r.desc || "", deny_mode: r.deny_mode || "deny_write" };
|
|
1670
1596
|
if (r.credential) out.credential = true;
|
|
@@ -1690,22 +1616,24 @@ function getDisabledL2RulesWithSkipL3() {
|
|
|
1690
1616
|
return {};
|
|
1691
1617
|
}
|
|
1692
1618
|
const result = {};
|
|
1693
|
-
const
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
if (
|
|
1700
|
-
if (
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1619
|
+
for (const layerKey of ["L1_rules", "L2_rules"]) {
|
|
1620
|
+
const layer = runtime[layerKey] || {};
|
|
1621
|
+
for (const [catName, cat] of Object.entries(layer)) {
|
|
1622
|
+
if (!cat.category_enabled) continue;
|
|
1623
|
+
const items = [];
|
|
1624
|
+
for (const r of cat.rules || []) {
|
|
1625
|
+
if (r.enabled === false && r.skip_l3_on_disabled) {
|
|
1626
|
+
if (catName === "sensitive_path_access") {
|
|
1627
|
+
if (r.path) items.push(r.path);
|
|
1628
|
+
} else if (catName === "intent_consistency") {
|
|
1629
|
+
items.push(...r.intent_keywords || []);
|
|
1630
|
+
} else if (r.pattern) {
|
|
1631
|
+
items.push(r.pattern);
|
|
1632
|
+
}
|
|
1705
1633
|
}
|
|
1706
1634
|
}
|
|
1635
|
+
if (items.length > 0) result[catName] = items;
|
|
1707
1636
|
}
|
|
1708
|
-
if (items.length > 0) result[catName] = items;
|
|
1709
1637
|
}
|
|
1710
1638
|
return result;
|
|
1711
1639
|
}
|
|
@@ -1866,15 +1794,14 @@ function generateSourceDefaults() {
|
|
|
1866
1794
|
category_desc: "Prompt \u6CE8\u5165\u653B\u51FB\u68C0\u6D4B",
|
|
1867
1795
|
rules: _l1InjectionKeywordsToRules()
|
|
1868
1796
|
},
|
|
1869
|
-
user_sensitive_actions: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49\u654F\u611F\u52A8\u4F5C/\u5DE5\u5177\u89C4\u5219", rules: [] },
|
|
1870
|
-
user_custom: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49\u547D\u4EE4\u89C4\u5219", rules: [] }
|
|
1871
|
-
},
|
|
1872
|
-
L2_rules: {
|
|
1873
1797
|
sensitive_path_access: {
|
|
1874
1798
|
category_enabled: true,
|
|
1875
|
-
category_desc: "\u654F\u611F\u8DEF\u5F84\u8BBF\u95EE\u68C0\u6D4B",
|
|
1799
|
+
category_desc: "\u654F\u611F\u8DEF\u5F84\u8BBF\u95EE\u68C0\u6D4B\uFF08deny_both/deny_read/deny_write\uFF09",
|
|
1876
1800
|
rules: _l2SensitivePathsToRules()
|
|
1877
1801
|
},
|
|
1802
|
+
user_custom: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49\u547D\u4EE4\u89C4\u5219", rules: [] }
|
|
1803
|
+
},
|
|
1804
|
+
L2_rules: {
|
|
1878
1805
|
intent_consistency: {
|
|
1879
1806
|
category_enabled: true,
|
|
1880
1807
|
category_desc: "\u610F\u56FE\u4E00\u81F4\u6027\u68C0\u6D4B",
|
|
@@ -1891,7 +1818,7 @@ function generateSourceDefaults() {
|
|
|
1891
1818
|
rules: _l2UserDeletionPatternsToRules()
|
|
1892
1819
|
},
|
|
1893
1820
|
read_before_write: { category_enabled: true, category_desc: "read_before_write \u5B89\u5168\u539F\u5219\u68C0\u6D4B", rules: [] },
|
|
1894
|
-
|
|
1821
|
+
user_custom: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49 L2 \u903B\u8F91\u89C4\u5219", rules: [] }
|
|
1895
1822
|
},
|
|
1896
1823
|
L3_skills: _l3SkillsToRules()
|
|
1897
1824
|
};
|
|
@@ -1959,6 +1886,10 @@ function _mergeRuleCategories(userCfg, srcDefaults, layerKey) {
|
|
|
1959
1886
|
}
|
|
1960
1887
|
}
|
|
1961
1888
|
}
|
|
1889
|
+
for (const catName of Object.keys(userLayer)) {
|
|
1890
|
+
if (catName === "user_custom") continue;
|
|
1891
|
+
if (!(catName in srcLayer)) delete userLayer[catName];
|
|
1892
|
+
}
|
|
1962
1893
|
}
|
|
1963
1894
|
function _mergeSkillCategories(userCfg, srcDefaults, layerKey) {
|
|
1964
1895
|
const userLayer = userCfg[layerKey] || (userCfg[layerKey] = {});
|
|
@@ -1985,11 +1916,42 @@ function mergeConfig(userCfg, srcDefaults) {
|
|
|
1985
1916
|
for (const [layerKey, defaultVal] of Object.entries(srcDefaults.layers)) {
|
|
1986
1917
|
if (!(layerKey in cfg.layers)) cfg.layers[layerKey] = defaultVal;
|
|
1987
1918
|
}
|
|
1919
|
+
_migrateCategoriesAcrossLayers(
|
|
1920
|
+
cfg,
|
|
1921
|
+
"L2_rules",
|
|
1922
|
+
"L1_rules",
|
|
1923
|
+
["sensitive_path_access"]
|
|
1924
|
+
);
|
|
1988
1925
|
_mergeRuleCategories(cfg, srcDefaults, "L1_rules");
|
|
1989
1926
|
_mergeRuleCategories(cfg, srcDefaults, "L2_rules");
|
|
1990
1927
|
_mergeSkillCategories(cfg, srcDefaults, "L3_skills");
|
|
1991
1928
|
return cfg;
|
|
1992
1929
|
}
|
|
1930
|
+
function _migrateCategoriesAcrossLayers(cfg, srcLayer, dstLayer, catNames) {
|
|
1931
|
+
const src = cfg[srcLayer] || {};
|
|
1932
|
+
const dst = cfg[dstLayer] || (cfg[dstLayer] = {});
|
|
1933
|
+
for (const catName of catNames) {
|
|
1934
|
+
if (!(catName in src)) continue;
|
|
1935
|
+
const srcCat = src[catName];
|
|
1936
|
+
if (!dst[catName]) {
|
|
1937
|
+
dst[catName] = { category_enabled: true, category_desc: "", rules: [] };
|
|
1938
|
+
}
|
|
1939
|
+
const dstCat = dst[catName];
|
|
1940
|
+
if (!dstCat.category_desc && srcCat.category_desc) dstCat.category_desc = srcCat.category_desc;
|
|
1941
|
+
if (dstCat.category_enabled === void 0) dstCat.category_enabled = srcCat.category_enabled;
|
|
1942
|
+
if (srcCat.rules && srcCat.rules.length > 0) {
|
|
1943
|
+
const dstFps = new Set((dstCat.rules || []).map((r) => _ruleFingerprint(r)));
|
|
1944
|
+
for (const r of srcCat.rules) {
|
|
1945
|
+
const fp = _ruleFingerprint(r);
|
|
1946
|
+
if (!dstFps.has(fp)) {
|
|
1947
|
+
(dstCat.rules = dstCat.rules || []).push(r);
|
|
1948
|
+
dstFps.add(fp);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
delete src[catName];
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1993
1955
|
function getEnabledL1InjectionKeywords(runtime) {
|
|
1994
1956
|
const cat = runtime.L1_rules?.injection_detection || { category_enabled: true, rules: [] };
|
|
1995
1957
|
return filterEnabledRules(cat.rules || [], cat.category_enabled).map((r) => ({
|
|
@@ -2142,7 +2104,8 @@ function deleteCustomRule(layer, category, ruleId) {
|
|
|
2142
2104
|
const rules = runtime[layer]?.[category]?.rules || [];
|
|
2143
2105
|
const idx = rules.findIndex((r) => r.id === ruleId);
|
|
2144
2106
|
if (idx >= 0) {
|
|
2145
|
-
|
|
2107
|
+
const r = rules[idx];
|
|
2108
|
+
if (r.builtin && !r.source_removed) return null;
|
|
2146
2109
|
rules.splice(idx, 1);
|
|
2147
2110
|
saveRuntimeConfig(runtime);
|
|
2148
2111
|
}
|
|
@@ -3359,9 +3322,11 @@ async function runAnalysis(input) {
|
|
|
3359
3322
|
}
|
|
3360
3323
|
}
|
|
3361
3324
|
const logicResult = isLogicRulesEnabled() ? runLogicCheck(input) : null;
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3325
|
+
const l1FileAccessHit = !!(heuristicResult && !heuristicResult.allowed && heuristicResult.riskType === "file_access");
|
|
3326
|
+
const effectiveResult = logicResult && !logicResult.allowed ? logicResult : l1FileAccessHit ? heuristicResult : null;
|
|
3327
|
+
if (effectiveResult) {
|
|
3328
|
+
const isCredentialPath = !!effectiveResult.isCredential;
|
|
3329
|
+
const skipInlineFileAccess = (isInlineScriptCmd || isLiteralTextCmd) && effectiveResult.riskType === "file_access";
|
|
3365
3330
|
if (skipInlineFileAccess) {
|
|
3366
3331
|
const inlineJudgment = analyzeInlineScript(input.aNext.actionDetail);
|
|
3367
3332
|
if (inlineJudgment.actionable) {
|
|
@@ -3387,8 +3352,8 @@ async function runAnalysis(input) {
|
|
|
3387
3352
|
};
|
|
3388
3353
|
}
|
|
3389
3354
|
}
|
|
3390
|
-
if ((
|
|
3391
|
-
return
|
|
3355
|
+
if ((effectiveResult.riskLevel === "high" || effectiveResult.riskLevel === "critical") && (!skipInlineFileAccess || isCredentialPath)) {
|
|
3356
|
+
return effectiveResult;
|
|
3392
3357
|
}
|
|
3393
3358
|
}
|
|
3394
3359
|
if (scriptChain && scriptChain.nodes.length > 0 && isLogicRulesEnabled()) {
|