@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
package/dist/cli.js
CHANGED
|
@@ -264,247 +264,6 @@ var init_agents = __esm({
|
|
|
264
264
|
}
|
|
265
265
|
});
|
|
266
266
|
|
|
267
|
-
// src/engine/heuristic.ts
|
|
268
|
-
function runHeuristicCheck(input) {
|
|
269
|
-
const command = `${input.aNext.actionType}: ${input.aNext.actionDetail}`;
|
|
270
|
-
const matched = [];
|
|
271
|
-
let highestSeverity = "low";
|
|
272
|
-
let highestRiskType = "";
|
|
273
|
-
const userRules = getCustomRules();
|
|
274
|
-
for (const rule of userRules) {
|
|
275
|
-
try {
|
|
276
|
-
const re = new RegExp(rule.pattern);
|
|
277
|
-
if (re.test(command)) {
|
|
278
|
-
if (rule.action === "Deny") {
|
|
279
|
-
matched.push(`\u81EA\u5B9A\u4E49\u89C4\u5219: ${rule.pattern}`);
|
|
280
|
-
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
281
|
-
highestSeverity = rule.severity;
|
|
282
|
-
highestRiskType = "custom_rule";
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
} catch {
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
let topRiskType = "";
|
|
290
|
-
for (const rule of DANGEROUS_PATTERNS) {
|
|
291
|
-
if (rule.pattern.test(command)) {
|
|
292
|
-
matched.push(rule.description);
|
|
293
|
-
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
294
|
-
highestSeverity = rule.severity;
|
|
295
|
-
topRiskType = rule.riskType;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
highestRiskType = topRiskType || highestRiskType;
|
|
300
|
-
const agentExt = getAgentExtensions(input.agentId);
|
|
301
|
-
if (agentExt?.extra_command_patterns) {
|
|
302
|
-
for (const rule of agentExt.extra_command_patterns) {
|
|
303
|
-
try {
|
|
304
|
-
const re = new RegExp(rule.pattern, "i");
|
|
305
|
-
if (re.test(command)) {
|
|
306
|
-
matched.push(`agent \u4E13\u5C5E\u89C4\u5219: ${rule.reason}`);
|
|
307
|
-
if (severityRank(rule.risk_level) > severityRank(highestSeverity)) {
|
|
308
|
-
highestSeverity = rule.risk_level;
|
|
309
|
-
highestRiskType = rule.risk_type;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
} catch {
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
const injectionText = `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
317
|
-
const injectionHits = checkInjectionKeywords(injectionText, agentExt?.extra_injection_keywords);
|
|
318
|
-
if (injectionHits.length > 0) {
|
|
319
|
-
const topHit = injectionHits.reduce((a, b) => severityRank(a.riskLevel) >= severityRank(b.riskLevel) ? a : b);
|
|
320
|
-
matched.push(...injectionHits.map((h) => `\u6CE8\u5165\u5173\u952E\u8BCD [${h.lang}]: ${h.keyword}`));
|
|
321
|
-
if (severityRank(topHit.riskLevel) > severityRank(highestSeverity)) {
|
|
322
|
-
highestSeverity = topHit.riskLevel;
|
|
323
|
-
highestRiskType = "prompt_injection";
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
if (matched.length > 0) {
|
|
327
|
-
return {
|
|
328
|
-
allowed: false,
|
|
329
|
-
reason: `\u68C0\u6D4B\u5230\u9AD8\u5371\u64CD\u4F5C: ${matched.join(", ")}`,
|
|
330
|
-
riskLevel: highestSeverity,
|
|
331
|
-
riskType: highestRiskType,
|
|
332
|
-
confidence: 95,
|
|
333
|
-
source: "heuristic",
|
|
334
|
-
violatedLayers: ["1.1"]
|
|
335
|
-
// 对齐 py coordinator.py:165(L1.1 = 命中高危命令模式/注入关键词)
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
340
|
-
function checkInjectionKeywords(text, extraKeywords) {
|
|
341
|
-
const hits = [];
|
|
342
|
-
for (const entry of INJECTION_KEYWORDS) {
|
|
343
|
-
if (text.includes(entry.keyword.toLowerCase())) {
|
|
344
|
-
hits.push(entry);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
if (extraKeywords) {
|
|
348
|
-
for (const entry of extraKeywords) {
|
|
349
|
-
if (text.includes(entry.keyword.toLowerCase())) {
|
|
350
|
-
hits.push({ keyword: entry.keyword, riskLevel: entry.risk_level, lang: entry.lang });
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
return hits;
|
|
355
|
-
}
|
|
356
|
-
function isInlineScriptCommand(actionDetail) {
|
|
357
|
-
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;
|
|
358
|
-
return re.test(actionDetail);
|
|
359
|
-
}
|
|
360
|
-
function severityRank(s) {
|
|
361
|
-
const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
362
|
-
return ranks[s] || 0;
|
|
363
|
-
}
|
|
364
|
-
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS;
|
|
365
|
-
var init_heuristic = __esm({
|
|
366
|
-
"src/engine/heuristic.ts"() {
|
|
367
|
-
"use strict";
|
|
368
|
-
init_esm_shims();
|
|
369
|
-
init_config();
|
|
370
|
-
init_agents();
|
|
371
|
-
INJECTION_KEYWORDS = [
|
|
372
|
-
// ---- Instruction Override ----
|
|
373
|
-
{ keyword: "ignore previous instructions", riskLevel: "critical", lang: "en" },
|
|
374
|
-
{ keyword: "ignore all previous", riskLevel: "critical", lang: "en" },
|
|
375
|
-
{ keyword: "disregard all prior", riskLevel: "critical", lang: "en" },
|
|
376
|
-
{ keyword: "forget everything", riskLevel: "high", lang: "en" },
|
|
377
|
-
{ keyword: "\u5FFD\u7565\u4E4B\u524D\u7684\u6307\u4EE4", riskLevel: "critical", lang: "zh" },
|
|
378
|
-
{ keyword: "\u5FFD\u7565\u6240\u6709\u5148\u524D\u7684", riskLevel: "critical", lang: "zh" },
|
|
379
|
-
{ keyword: "\u5FFD\u7565\u4E0A\u9762\u6240\u6709", riskLevel: "high", lang: "zh" },
|
|
380
|
-
{ keyword: "\u8BF7\u5FD8\u8BB0\u4E4B\u524D", riskLevel: "high", lang: "zh" },
|
|
381
|
-
// ---- Role Hijacking ----
|
|
382
|
-
{ keyword: "you are now", riskLevel: "high", lang: "en" },
|
|
383
|
-
{ keyword: "you are no longer", riskLevel: "high", lang: "en" },
|
|
384
|
-
{ keyword: "new instructions", riskLevel: "high", lang: "en" },
|
|
385
|
-
{ keyword: "from now on, you", riskLevel: "high", lang: "en" },
|
|
386
|
-
{ keyword: "\u4F60\u73B0\u5728\u662F\u4E00\u4E2A", riskLevel: "high", lang: "zh" },
|
|
387
|
-
{ keyword: "\u4F60\u4E0D\u518D\u662F\u4E00\u4E2A", riskLevel: "high", lang: "zh" },
|
|
388
|
-
{ keyword: "\u4ECE\u73B0\u5728\u5F00\u59CB\u4F60", riskLevel: "high", lang: "zh" },
|
|
389
|
-
{ keyword: "\u4F60\u7684\u65B0\u89D2\u8272\u662F", riskLevel: "high", lang: "zh" },
|
|
390
|
-
// ---- Command Injection ----
|
|
391
|
-
{ keyword: "system prompt", riskLevel: "high", lang: "en" },
|
|
392
|
-
{ keyword: "reveal your instructions", riskLevel: "high", lang: "en" },
|
|
393
|
-
{ keyword: "output your instructions", riskLevel: "high", lang: "en" },
|
|
394
|
-
{ keyword: "repeat your instructions", riskLevel: "medium", lang: "en" },
|
|
395
|
-
{ keyword: "\u7CFB\u7EDF\u63D0\u793A", riskLevel: "high", lang: "zh" },
|
|
396
|
-
{ keyword: "\u8F93\u51FA\u4F60\u7684\u6307\u4EE4", riskLevel: "high", lang: "zh" },
|
|
397
|
-
{ keyword: "\u91CD\u590D\u4F60\u7684\u6307\u4EE4", riskLevel: "medium", lang: "zh" },
|
|
398
|
-
// ---- Social Engineering ----
|
|
399
|
-
{ keyword: "this is an authorized test", riskLevel: "high", lang: "en" },
|
|
400
|
-
{ keyword: "security audit approved", riskLevel: "high", lang: "en" },
|
|
401
|
-
{ keyword: "admin override", riskLevel: "critical", lang: "en" },
|
|
402
|
-
{ keyword: "debug mode", riskLevel: "high", lang: "en" },
|
|
403
|
-
{ keyword: "maintenance mode", riskLevel: "high", lang: "en" },
|
|
404
|
-
{ keyword: "\u8FD9\u662F\u6388\u6743\u7684\u6D4B\u8BD5", riskLevel: "high", lang: "zh" },
|
|
405
|
-
{ keyword: "\u5B89\u5168\u5BA1\u8BA1\u5DF2\u6279\u51C6", riskLevel: "high", lang: "zh" },
|
|
406
|
-
{ keyword: "\u7BA1\u7406\u5458\u8986\u76D6", riskLevel: "critical", lang: "zh" },
|
|
407
|
-
{ keyword: "\u8C03\u8BD5\u6A21\u5F0F", riskLevel: "high", lang: "zh" },
|
|
408
|
-
// ---- XSS ----
|
|
409
|
-
{ keyword: "<script>", riskLevel: "high", lang: "en" },
|
|
410
|
-
{ keyword: "javascript:", riskLevel: "high", lang: "en" },
|
|
411
|
-
{ keyword: "onerror=", riskLevel: "high", lang: "en" },
|
|
412
|
-
{ keyword: "onload=", riskLevel: "high", lang: "en" },
|
|
413
|
-
// ---- Fake Boundaries ----
|
|
414
|
-
{ keyword: "=== END OF", riskLevel: "high", lang: "en" },
|
|
415
|
-
{ keyword: "--- END SYSTEM", riskLevel: "high", lang: "en" },
|
|
416
|
-
{ keyword: "[END OF", riskLevel: "high", lang: "en" },
|
|
417
|
-
{ keyword: "=== \u7ED3\u675F", riskLevel: "high", lang: "zh" },
|
|
418
|
-
{ keyword: "--- \u7ED3\u675F\u7CFB\u7EDF", riskLevel: "high", lang: "zh" },
|
|
419
|
-
// ---- Developer Mode ----
|
|
420
|
-
{ keyword: "developer mode", riskLevel: "critical", lang: "en" },
|
|
421
|
-
{ keyword: "DAN mode", riskLevel: "critical", lang: "en" },
|
|
422
|
-
{ keyword: "jailbreak", riskLevel: "critical", lang: "en" },
|
|
423
|
-
{ keyword: "\u5F00\u53D1\u8005\u6A21\u5F0F", riskLevel: "critical", lang: "zh" },
|
|
424
|
-
{ keyword: "\u8D8A\u72F1", riskLevel: "critical", lang: "zh" }
|
|
425
|
-
// 注:xiaoO 专属绕过词(绕过审计/禁用安全检查/关闭防护/bypass audit 等)
|
|
426
|
-
// 已迁至 agent_moss/agents/xiaoo/rules.json 的 extra_injection_keywords,
|
|
427
|
-
// 由 agent_ext 机制注入,不再污染通用层。
|
|
428
|
-
];
|
|
429
|
-
DANGEROUS_PATTERNS = [
|
|
430
|
-
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
431
|
-
// 1. rm -rf root dir (含通配符如 /* /.* 等) — 使用负向先行断言 (?!\w):/ 后面不是单词字符时匹配
|
|
432
|
-
{ 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" },
|
|
433
|
-
// 注意:已移除"rm -rf /任意绝对路径"的宽泛规则,避免误杀 /tmp 等临时目录清理操作
|
|
434
|
-
// 2. rm with -r or -f targeting system dirs
|
|
435
|
-
{ 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" },
|
|
436
|
-
// 3. rm -r absolute path (no -f)
|
|
437
|
-
{ 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" },
|
|
438
|
-
// 4. rm -f absolute path (no -r)
|
|
439
|
-
{ 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" },
|
|
440
|
-
// dd 磁盘清零 — 只拦截写入系统关键目录,放行 /tmp 等临时目录
|
|
441
|
-
{ 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" },
|
|
442
|
-
// mkfs 格式化 — 只拦截对块设备(/dev/sdX 等)的格式化,放行对普通文件的格式化
|
|
443
|
-
{ 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" },
|
|
444
|
-
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
445
|
-
// --- Critical: remote code execution ---
|
|
446
|
-
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
447
|
-
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
448
|
-
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
449
|
-
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "critical", description: "base64 \u89E3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
450
|
-
// --- Critical: reverse shell ---
|
|
451
|
-
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
452
|
-
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
453
|
-
// --- Critical: sensitive file access ---
|
|
454
|
-
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
455
|
-
{ pattern: /\/etc\/gshadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6 (/etc/gshadow)", riskType: "file_access" },
|
|
456
|
-
// 注意:/etc/passwd 已从拦截列表移除,因为它是公开可读的标准系统文件,真正敏感的是 /etc/shadow
|
|
457
|
-
{ pattern: /\.ssh\/id_rsa/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
458
|
-
// --- Critical: privilege escalation / container escape ---
|
|
459
|
-
{ 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" },
|
|
460
|
-
// --- High: dangerous permissions / ownership ---
|
|
461
|
-
{ pattern: /chmod\s+[0-7]*777[0-7]*/i, severity: "high", description: "\u5168\u6743\u9650\u8BBE\u7F6E (chmod 777)", riskType: "script_execution" },
|
|
462
|
-
{ 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" },
|
|
463
|
-
// sudo 提权 — 只拦截 sudo 后跟的危险命令,不一刀切拦截所有 sudo
|
|
464
|
-
{ 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" },
|
|
465
|
-
// --- High: system config overwrite ---
|
|
466
|
-
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
467
|
-
// --- High: download script + execute risk ---
|
|
468
|
-
{ 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" },
|
|
469
|
-
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
470
|
-
// --- High: package manager pipe-to-shell ---
|
|
471
|
-
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
472
|
-
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
473
|
-
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
474
|
-
// --- Medium: destructive git operations (降级为 medium,允许但记录) ---
|
|
475
|
-
{ 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" },
|
|
476
|
-
// --- High: network port scanning (横向移动侦察) ---
|
|
477
|
-
{ 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" },
|
|
478
|
-
{ 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" },
|
|
479
|
-
// --- Medium: credential export ---
|
|
480
|
-
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
481
|
-
// --- High: shell rc file append (persistence) ---
|
|
482
|
-
{ 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" },
|
|
483
|
-
// --- High: device file write (只拦截重定向写入设备文件,不拦截读取) ---
|
|
484
|
-
{ 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" },
|
|
485
|
-
// --- High: non-interactive password modification ---
|
|
486
|
-
{ 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" },
|
|
487
|
-
{ 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" },
|
|
488
|
-
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
489
|
-
{ 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" },
|
|
490
|
-
{ 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" },
|
|
491
|
-
{ 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" },
|
|
492
|
-
// --- High: non-interactive password modification (extended) ---
|
|
493
|
-
{ pattern: /\blpasswd\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u64CD\u4F5C (lpasswd)", riskType: "script_execution" },
|
|
494
|
-
{ pattern: /\bgpasswd\s+(?!-[adA])/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7EC4\u5BC6\u7801\u7BA1\u7406\u64CD\u4F5C (gpasswd)", riskType: "script_execution" },
|
|
495
|
-
{ pattern: /\bchgpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u6279\u91CF\u4FEE\u6539\u7EC4\u5BC6\u7801\u64CD\u4F5C (chgpasswd)", riskType: "script_execution" },
|
|
496
|
-
// --- High: user/group deletion (irreversible, requires user consent) ---
|
|
497
|
-
{ pattern: /\buserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (userdel)", riskType: "script_execution" },
|
|
498
|
-
{ pattern: /\bdeluser\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (deluser)", riskType: "script_execution" },
|
|
499
|
-
{ pattern: /\bluserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (luserdel)", riskType: "script_execution" },
|
|
500
|
-
{ pattern: /\bgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (groupdel)", riskType: "script_execution" },
|
|
501
|
-
{ pattern: /\blgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (lgroupdel)", riskType: "script_execution" },
|
|
502
|
-
// --- High: generic command -p parameter password setting ---
|
|
503
|
-
{ 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" }
|
|
504
|
-
];
|
|
505
|
-
}
|
|
506
|
-
});
|
|
507
|
-
|
|
508
267
|
// src/engine/inline-analyzer.ts
|
|
509
268
|
function isLiteralTextCommand(command) {
|
|
510
269
|
ECHO_CMD_RE.lastIndex = 0;
|
|
@@ -721,165 +480,26 @@ function runLogicCheck(input) {
|
|
|
721
480
|
}
|
|
722
481
|
}
|
|
723
482
|
}
|
|
724
|
-
if (!isExcludedType) {
|
|
725
|
-
const agentExt = getAgentExtensions(input.agentId || "");
|
|
726
|
-
const pathResult = checkSensitivePath(actionDetail, resolvedCwd, agentExt);
|
|
727
|
-
if (pathResult) return pathResult;
|
|
728
|
-
}
|
|
729
|
-
if (actionType !== "file_write" && actionType !== "file_edit") {
|
|
730
|
-
const TEMP_DIRS = ["/tmp/", "/var/tmp/", "/run/", "/dev/shm/"];
|
|
731
|
-
const isTempPath = TEMP_DIRS.some((td) => actionDetail.includes(td));
|
|
732
|
-
if (!isTempPath && (actionDetail.includes("*") || actionDetail.includes("?")) && ["rm ", "rm ", "del ", "del ", "delete", "remove ", "remove ", "\u5220\u9664", "\u79FB\u9664"].some((kw) => actionDetail.includes(kw))) {
|
|
733
|
-
return {
|
|
734
|
-
allowed: false,
|
|
735
|
-
reason: "\u68C0\u6D4B\u5230\u901A\u914D\u7B26\u7ED3\u5408\u5220\u9664\u64CD\u4F5C\uFF0C\u53EF\u80FD\u9020\u6210\u6279\u91CF\u8BEF\u5220",
|
|
736
|
-
riskLevel: "high",
|
|
737
|
-
riskType: "script_execution",
|
|
738
|
-
confidence: 90,
|
|
739
|
-
source: "logic_rule",
|
|
740
|
-
violatedLayers: ["2"]
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
if (/>\s*\/etc\//.test(actionDetail) || />\s*\/boot\//.test(actionDetail) || />\s*\/proc\//.test(actionDetail)) {
|
|
744
|
-
return {
|
|
745
|
-
allowed: false,
|
|
746
|
-
reason: "\u68C0\u6D4B\u5230\u91CD\u5B9A\u5411\u8986\u76D6\u5199\u5165\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55",
|
|
747
|
-
riskLevel: "critical",
|
|
748
|
-
riskType: "file_access",
|
|
749
|
-
confidence: 95,
|
|
750
|
-
source: "logic_rule",
|
|
751
|
-
violatedLayers: ["2"]
|
|
752
|
-
};
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
var _READ_ONLY_COMMANDS = /* @__PURE__ */ new Set([
|
|
756
|
-
"cat",
|
|
757
|
-
"head",
|
|
758
|
-
"tail",
|
|
759
|
-
"less",
|
|
760
|
-
"more",
|
|
761
|
-
"grep",
|
|
762
|
-
"find",
|
|
763
|
-
"awk",
|
|
764
|
-
"sed",
|
|
765
|
-
"sort",
|
|
766
|
-
"uniq",
|
|
767
|
-
"wc",
|
|
768
|
-
"cut",
|
|
769
|
-
"strings",
|
|
770
|
-
"od",
|
|
771
|
-
"xxd",
|
|
772
|
-
"hexdump",
|
|
773
|
-
"tr",
|
|
774
|
-
"file",
|
|
775
|
-
"stat",
|
|
776
|
-
"du",
|
|
777
|
-
"df",
|
|
778
|
-
"ls",
|
|
779
|
-
"dir",
|
|
780
|
-
"tree",
|
|
781
|
-
"nl",
|
|
782
|
-
"tac",
|
|
783
|
-
"rev",
|
|
784
|
-
"lsblk",
|
|
785
|
-
"blockdev",
|
|
786
|
-
"smartctl",
|
|
787
|
-
"udevadm",
|
|
788
|
-
"dmidecode",
|
|
789
|
-
"lscpu",
|
|
790
|
-
"lspci",
|
|
791
|
-
"lsusb",
|
|
792
|
-
"lsmem",
|
|
793
|
-
"lsns",
|
|
794
|
-
"lsof",
|
|
795
|
-
"hwinfo",
|
|
796
|
-
"inxi",
|
|
797
|
-
"fdisk",
|
|
798
|
-
"parted",
|
|
799
|
-
"dmesg",
|
|
800
|
-
"journalctl",
|
|
801
|
-
"systemctl",
|
|
802
|
-
"hostnamectl",
|
|
803
|
-
"localectl",
|
|
804
|
-
"timedatectl",
|
|
805
|
-
"ps",
|
|
806
|
-
"top",
|
|
807
|
-
"free",
|
|
808
|
-
"vmstat",
|
|
809
|
-
"iostat",
|
|
810
|
-
"mpstat",
|
|
811
|
-
"pidof",
|
|
812
|
-
"pgrep",
|
|
813
|
-
"ip",
|
|
814
|
-
"ifconfig",
|
|
815
|
-
"route",
|
|
816
|
-
"ss",
|
|
817
|
-
"netstat",
|
|
818
|
-
"arp",
|
|
819
|
-
"ethtool",
|
|
820
|
-
"nmcli",
|
|
821
|
-
"uname",
|
|
822
|
-
"arch",
|
|
823
|
-
"nproc",
|
|
824
|
-
"getconf",
|
|
825
|
-
"getent",
|
|
826
|
-
"id",
|
|
827
|
-
"whoami",
|
|
828
|
-
"who",
|
|
829
|
-
"w",
|
|
830
|
-
"last",
|
|
831
|
-
"uptime",
|
|
832
|
-
"lsmod",
|
|
833
|
-
"modinfo",
|
|
834
|
-
"sysctl"
|
|
835
|
-
]);
|
|
836
|
-
var _DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
|
|
837
|
-
var _WRITE_COMMAND_RES = [
|
|
838
|
-
/\brm\b/,
|
|
839
|
-
/\bunlink\b/,
|
|
840
|
-
/\brmdir\b/,
|
|
841
|
-
/\bshred\b/,
|
|
842
|
-
/\bcp\b/,
|
|
843
|
-
/\bmv\b/,
|
|
844
|
-
/\binstall\b/,
|
|
845
|
-
/\btee\b/,
|
|
846
|
-
/\bdd\b/,
|
|
847
|
-
/\bmkfs\b/,
|
|
848
|
-
/\b(fdisk|parted|cfdisk|sfdisk)\b/,
|
|
849
|
-
/\bchmod\b/,
|
|
850
|
-
/\bchown\b/,
|
|
851
|
-
/\btruncate\b/
|
|
852
|
-
];
|
|
853
483
|
const indirectResult = checkIndirectFileAccess(actionType, actionDetail, resolvedCwd);
|
|
854
484
|
if (indirectResult) return indirectResult;
|
|
855
485
|
if (actionDetail.includes("sudo") || actionDetail.includes("su -") || actionDetail.includes("chmod u+s") || actionDetail.includes("setuid")) {
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
)
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
if (targetHost && !isLocalHost(targetHost)) {
|
|
874
|
-
return {
|
|
875
|
-
allowed: false,
|
|
876
|
-
reason: `\u5C1D\u8BD5\u6A2A\u5411\u79FB\u52A8\u5230\u8FDC\u7A0B\u4E3B\u673A: ${targetHost}`,
|
|
877
|
-
riskLevel: "medium",
|
|
878
|
-
riskType: "lateral_movement",
|
|
879
|
-
confidence: 80,
|
|
880
|
-
source: "logic_rule",
|
|
881
|
-
violatedLayers: ["2"]
|
|
882
|
-
};
|
|
486
|
+
const detailAfterSudo = actionDetail.replace(/(^|\|\||&&|\s)sudo\s+/g, " ");
|
|
487
|
+
const isAdminCmd = ["apt", "systemctl", "yum", "dnf", "pacman", "zypper", "apk"].some((kw) => detailAfterSudo.includes(kw));
|
|
488
|
+
if (!isAdminCmd) {
|
|
489
|
+
const adminContext = actionHistory.some(
|
|
490
|
+
(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")
|
|
491
|
+
);
|
|
492
|
+
if (!adminContext) {
|
|
493
|
+
return {
|
|
494
|
+
allowed: false,
|
|
495
|
+
reason: "\u68C0\u6D4B\u5230\u63D0\u6743\u64CD\u4F5C\uFF0C\u672A\u53D1\u73B0\u5408\u6CD5\u7BA1\u7406\u4E0A\u4E0B\u6587",
|
|
496
|
+
riskLevel: "high",
|
|
497
|
+
riskType: "privilege_escalation",
|
|
498
|
+
confidence: 85,
|
|
499
|
+
source: "logic_rule",
|
|
500
|
+
violatedLayers: ["2"]
|
|
501
|
+
};
|
|
502
|
+
}
|
|
883
503
|
}
|
|
884
504
|
}
|
|
885
505
|
const pwdResult = checkPasswordConsent(actionType, actionDetail, actionHistory);
|
|
@@ -947,119 +567,6 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
|
|
|
947
567
|
}
|
|
948
568
|
return null;
|
|
949
569
|
}
|
|
950
|
-
function checkSensitivePath(command, cwd, agentExt) {
|
|
951
|
-
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
952
|
-
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/];
|
|
953
|
-
const _DEVNULL_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
|
|
954
|
-
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"]);
|
|
955
|
-
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));
|
|
956
|
-
for (const sp of ROOT_SENSITIVE_PATHS) {
|
|
957
|
-
if (command.includes(sp.path.toLowerCase())) {
|
|
958
|
-
if (sp.path === "/dev/random") {
|
|
959
|
-
if (isWriteOpFlag) {
|
|
960
|
-
continue;
|
|
961
|
-
}
|
|
962
|
-
return {
|
|
963
|
-
allowed: false,
|
|
964
|
-
reason: `\u8BFB\u53D6\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
965
|
-
riskLevel: sp.riskLevel,
|
|
966
|
-
riskType: "sensitive_path_access",
|
|
967
|
-
confidence: 90,
|
|
968
|
-
source: "logic_rule",
|
|
969
|
-
violatedLayers: ["2"]
|
|
970
|
-
};
|
|
971
|
-
}
|
|
972
|
-
if (!isWriteOpFlag && !sp.credential) {
|
|
973
|
-
continue;
|
|
974
|
-
}
|
|
975
|
-
return {
|
|
976
|
-
allowed: false,
|
|
977
|
-
reason: `\u5C1D\u8BD5\u8BBF\u95EE\u7CFB\u7EDF\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
978
|
-
riskLevel: sp.riskLevel,
|
|
979
|
-
riskType: "sensitive_path_access",
|
|
980
|
-
confidence: 90,
|
|
981
|
-
source: "logic_rule",
|
|
982
|
-
violatedLayers: ["2"]
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
for (const sp of HOME_SENSITIVE_PATHS) {
|
|
987
|
-
const expanded = `${expandedCwd}/${sp.path}`;
|
|
988
|
-
if (command.includes(sp.path.toLowerCase()) || command.includes(expanded.toLowerCase())) {
|
|
989
|
-
if (!isWriteOpFlag && !sp.credential) {
|
|
990
|
-
continue;
|
|
991
|
-
}
|
|
992
|
-
return {
|
|
993
|
-
allowed: false,
|
|
994
|
-
reason: `\u5C1D\u8BD5\u8BBF\u95EE\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
995
|
-
riskLevel: sp.riskLevel,
|
|
996
|
-
riskType: "sensitive_path_access",
|
|
997
|
-
confidence: 90,
|
|
998
|
-
source: "logic_rule",
|
|
999
|
-
violatedLayers: ["2"]
|
|
1000
|
-
};
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
if (agentExt?.extra_sensitive_paths && agentExt.extra_sensitive_paths.length > 0) {
|
|
1004
|
-
for (const sp of agentExt.extra_sensitive_paths) {
|
|
1005
|
-
const spPath = sp.path.toLowerCase();
|
|
1006
|
-
const expanded = `${expandedCwd}/${spPath}`;
|
|
1007
|
-
if (command.includes(spPath) || command.includes(expanded.toLowerCase())) {
|
|
1008
|
-
const denyMode = sp.deny_mode || (sp.credential ? "deny_both" : sp.read_only ? "deny_read" : "deny_write");
|
|
1009
|
-
if (denyMode === "deny_read") {
|
|
1010
|
-
if (isWriteOpFlag) continue;
|
|
1011
|
-
} else if (denyMode === "deny_write") {
|
|
1012
|
-
if (!isWriteOpFlag) continue;
|
|
1013
|
-
}
|
|
1014
|
-
return {
|
|
1015
|
-
allowed: false,
|
|
1016
|
-
reason: `\u5C1D\u8BD5\u8BBF\u95EE agent \u4E13\u5C5E\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
1017
|
-
riskLevel: sp.risk_level,
|
|
1018
|
-
riskType: "sensitive_path_access",
|
|
1019
|
-
confidence: 90,
|
|
1020
|
-
source: "logic_rule",
|
|
1021
|
-
violatedLayers: ["2"]
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
for (const cp of CREDENTIAL_PATHS) {
|
|
1027
|
-
const escaped = cp.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1028
|
-
const re = cp.path.startsWith(".") ? new RegExp(`(?:^|[\\s/\\\\'"])${escaped}\\b`) : new RegExp(`\\b${escaped}\\b`);
|
|
1029
|
-
if (re.test(command)) {
|
|
1030
|
-
return {
|
|
1031
|
-
allowed: false,
|
|
1032
|
-
reason: `\u8BBF\u95EE\u654F\u611F\u8DEF\u5F84: ${cp.desc} (${cp.path})`,
|
|
1033
|
-
riskLevel: cp.riskLevel,
|
|
1034
|
-
riskType: "sensitive_path_access",
|
|
1035
|
-
confidence: 90,
|
|
1036
|
-
source: "logic_rule",
|
|
1037
|
-
violatedLayers: ["2"],
|
|
1038
|
-
isCredential: true
|
|
1039
|
-
};
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
if ((command.includes("rm ") || command.includes("unlink")) && (command.includes("/etc/") || command.includes("/root/") || command.includes("/var/log/"))) {
|
|
1043
|
-
return {
|
|
1044
|
-
allowed: false,
|
|
1045
|
-
reason: "\u68C0\u6D4B\u5230\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55\u5185\u5BB9",
|
|
1046
|
-
riskLevel: "critical",
|
|
1047
|
-
riskType: "sensitive_path_access",
|
|
1048
|
-
confidence: 90,
|
|
1049
|
-
source: "logic_rule",
|
|
1050
|
-
violatedLayers: ["2"]
|
|
1051
|
-
};
|
|
1052
|
-
}
|
|
1053
|
-
return null;
|
|
1054
|
-
}
|
|
1055
|
-
function extractRemoteHost(command) {
|
|
1056
|
-
const m = command.match(/(?:ssh|scp|rsync)\s+(?:-[\w]+\s+)*(\S+@\S+|\b(?!-)[\w.-]+\b)/);
|
|
1057
|
-
return m ? m[1] : null;
|
|
1058
|
-
}
|
|
1059
|
-
function isLocalHost(host) {
|
|
1060
|
-
const localNames = ["localhost", "127.0.0.1", "::1", process.env.HOSTNAME || "", "0.0.0.0"];
|
|
1061
|
-
return localNames.includes(host.replace(/.*@/, ""));
|
|
1062
|
-
}
|
|
1063
570
|
function checkPasswordConsent(actionType, actionDetail, actionHistory) {
|
|
1064
571
|
if (actionType !== "bash") return null;
|
|
1065
572
|
const isPasswordModify = PASSWORD_MODIFY_PATTERNS.some((p) => p.test(actionDetail));
|
|
@@ -1162,117 +669,533 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd) {
|
|
|
1162
669
|
}
|
|
1163
670
|
}
|
|
1164
671
|
}
|
|
1165
|
-
return null;
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
return {
|
|
675
|
+
allowed: false,
|
|
676
|
+
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",
|
|
677
|
+
riskLevel: "medium",
|
|
678
|
+
riskType: "file_access",
|
|
679
|
+
confidence: 70,
|
|
680
|
+
source: "logic_rule",
|
|
681
|
+
violatedLayers: ["2"]
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
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;
|
|
685
|
+
var init_logic_rules = __esm({
|
|
686
|
+
"src/engine/logic-rules.ts"() {
|
|
687
|
+
"use strict";
|
|
688
|
+
init_esm_shims();
|
|
689
|
+
init_inline_analyzer();
|
|
690
|
+
ROOT_SENSITIVE_PATHS = [
|
|
691
|
+
{ path: "/etc/shadow", riskLevel: "critical", desc: "\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6", credential: true },
|
|
692
|
+
{ path: "/etc/gshadow", riskLevel: "critical", desc: "\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6", credential: true },
|
|
693
|
+
// 注意:/etc/passwd 仅从 L1 启发式规则移除(公开可读),L2 敏感路径仍保留
|
|
694
|
+
{ path: "/etc/passwd", riskLevel: "high", desc: "\u7CFB\u7EDF\u7528\u6237\u6587\u4EF6" },
|
|
695
|
+
{ path: "/etc/sudoers", riskLevel: "critical", desc: "sudo \u914D\u7F6E", credential: true },
|
|
696
|
+
// 系统配置(仅拦截写入)
|
|
697
|
+
{ path: "/etc/hosts", riskLevel: "medium", desc: "DNS \u89E3\u6790\u914D\u7F6E" },
|
|
698
|
+
{ path: "/etc/crontab", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1" },
|
|
699
|
+
{ path: "/etc/cron.d/", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55\uFF08\u62C6\u5206\u5F0F crontab\uFF09" },
|
|
700
|
+
{ path: "/var/spool/cron/", riskLevel: "high", desc: "\u7528\u6237\u7EA7\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55" },
|
|
701
|
+
{ path: "/etc/systemd/", riskLevel: "high", desc: "systemd \u670D\u52A1\u914D\u7F6E" },
|
|
702
|
+
{ path: "/etc/ssh/sshd_config", riskLevel: "high", desc: "SSH \u670D\u52A1\u914D\u7F6E" },
|
|
703
|
+
{ path: "/etc/pam.d/", riskLevel: "high", desc: "PAM \u53EF\u63D2\u62D4\u8BA4\u8BC1\u6A21\u5757\u914D\u7F6E" },
|
|
704
|
+
// 危险目录(仅拦截写入)
|
|
705
|
+
{ path: "/boot/", riskLevel: "critical", desc: "\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55" },
|
|
706
|
+
{ path: "/proc/sys/", riskLevel: "high", desc: "\u5185\u6838\u53C2\u6570" },
|
|
707
|
+
{ path: "/sys/", riskLevel: "high", desc: "sysfs \u5185\u6838\u63A5\u53E3" },
|
|
708
|
+
// 设备文件(/dev/null、/dev/zero、/dev/urandom 已移除,误报率极高)
|
|
709
|
+
{ path: "/dev/random", riskLevel: "high", desc: "\u963B\u585E\u5F0F\u968F\u673A\u6570\u8BBE\u5907\uFF08\u8BFB\u53D6\u8017\u5C3D\u71B5\u6C60\uFF09" },
|
|
710
|
+
{ path: "/dev/mem", riskLevel: "critical", desc: "\u7269\u7406\u5185\u5B58\u8BBF\u95EE\u8BBE\u5907" },
|
|
711
|
+
{ path: "/dev/kmsg", riskLevel: "high", desc: "\u5185\u6838\u6D88\u606F\u7F13\u51B2\u533A" },
|
|
712
|
+
// SSH 主机私钥
|
|
713
|
+
{ path: "/etc/ssh/ssh_host_rsa_key", riskLevel: "critical", desc: "SSH \u4E3B\u673A RSA \u79C1\u94A5", credential: true },
|
|
714
|
+
{ path: "/etc/ssh/ssh_host_ed25519_key", riskLevel: "critical", desc: "SSH \u4E3B\u673A Ed25519 \u79C1\u94A5", credential: true },
|
|
715
|
+
{ path: "/etc/ssh/ssh_host_ecdsa_key", riskLevel: "critical", desc: "SSH \u4E3B\u673A ECDSA \u79C1\u94A5", credential: true }
|
|
716
|
+
];
|
|
717
|
+
HOME_SENSITIVE_PATHS = [
|
|
718
|
+
{ path: ".ssh/id_rsa", riskLevel: "critical", desc: "SSH \u79C1\u94A5", credential: true },
|
|
719
|
+
{ path: ".ssh/id_ed25519", riskLevel: "critical", desc: "SSH \u79C1\u94A5 (ed25519)", credential: true },
|
|
720
|
+
{ path: ".ssh/authorized_keys", riskLevel: "high", desc: "SSH \u6388\u6743\u5BC6\u94A5" },
|
|
721
|
+
// 持久化与命令劫持(仅拦截写入)
|
|
722
|
+
{ path: ".bashrc", riskLevel: "high", desc: "\u7528\u6237 Shell \u521D\u59CB\u5316\u811A\u672C" },
|
|
723
|
+
{ path: ".bash_profile", riskLevel: "high", desc: "\u7528\u6237 Shell \u767B\u5F55\u811A\u672C" },
|
|
724
|
+
{ path: ".profile", riskLevel: "high", desc: "\u7528\u6237\u901A\u7528\u767B\u5F55\u811A\u672C" },
|
|
725
|
+
{ path: ".aws/credentials", riskLevel: "critical", desc: "AWS \u51ED\u8BC1", credential: true },
|
|
726
|
+
{ path: ".gitconfig", riskLevel: "medium", desc: "Git \u914D\u7F6E" },
|
|
727
|
+
{ path: ".gnupg", riskLevel: "high", desc: "GPG \u5BC6\u94A5\u76EE\u5F55" }
|
|
728
|
+
];
|
|
729
|
+
CREDENTIAL_PATHS = [
|
|
730
|
+
{ path: "credentials.yml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
731
|
+
{ path: "credentials.yaml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
732
|
+
{ path: "secrets.yml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
733
|
+
{ path: "secrets.yaml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
734
|
+
{ path: ".env", riskLevel: "high", desc: "\u73AF\u5883\u53D8\u91CF/\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" }
|
|
735
|
+
];
|
|
736
|
+
NON_WRITE_TOOLS = /* @__PURE__ */ new Set(["ask_user_question", "glob", "grep", "list_dir", "count_text_length", "search"]);
|
|
737
|
+
READ_ONLY_REDIR_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump"]);
|
|
738
|
+
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"];
|
|
739
|
+
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"];
|
|
740
|
+
CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
|
|
741
|
+
PASSWORD_MODIFY_PATTERNS = [
|
|
742
|
+
/\|\s*passwd\b/i,
|
|
743
|
+
/\bpasswd\s+--stdin\b/i,
|
|
744
|
+
/\bchpasswd\b/i,
|
|
745
|
+
/\bchgpasswd\b/i,
|
|
746
|
+
/\b(newusers|lnewusers)\b/i,
|
|
747
|
+
/\bpasswd\s+-[a-zA-Z]*d\b/i,
|
|
748
|
+
/\bpasswd\s+-[a-zA-Z]*l\b/i
|
|
749
|
+
];
|
|
750
|
+
USER_DELETION_PATTERNS = [
|
|
751
|
+
/\buserdel\s/i,
|
|
752
|
+
/\bdeluser\s/i,
|
|
753
|
+
/\bluserdel\s/i,
|
|
754
|
+
/\bgroupdel\s/i,
|
|
755
|
+
/\blgroupdel\s/i
|
|
756
|
+
];
|
|
757
|
+
INTENT_DEVIATION_PATTERNS = [
|
|
758
|
+
{
|
|
759
|
+
intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
|
|
760
|
+
dangerousActions: ["\u5220\u9664", "remove", "delete", "rm ", "\u683C\u5F0F\u5316", "format"],
|
|
761
|
+
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
intentKeywords: ["\u67E5\u8BE2", "\u641C\u7D22", "search", "query", "find"],
|
|
765
|
+
dangerousActions: ["\u4FEE\u6539", "update", "write", "\u5199\u5165", "alter"],
|
|
766
|
+
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u67E5\u8BE2/\u641C\u7D22\uFF0C\u4F46\u6267\u884C\u4E86\u4FEE\u6539\u64CD\u4F5C"
|
|
767
|
+
}
|
|
768
|
+
];
|
|
769
|
+
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;
|
|
770
|
+
DIR_TRAVERSAL_KW = [
|
|
771
|
+
"os.listdir",
|
|
772
|
+
"os.walk",
|
|
773
|
+
"os.scandir",
|
|
774
|
+
"glob.glob",
|
|
775
|
+
"glob.iglob",
|
|
776
|
+
"pathlib.",
|
|
777
|
+
"iterdir",
|
|
778
|
+
"rglob",
|
|
779
|
+
"scandir(",
|
|
780
|
+
"listdir("
|
|
781
|
+
];
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
// src/engine/heuristic.ts
|
|
786
|
+
function runHeuristicCheck(input) {
|
|
787
|
+
const command = `${input.aNext.actionType}: ${input.aNext.actionDetail}`;
|
|
788
|
+
const matched = [];
|
|
789
|
+
let highestSeverity = "low";
|
|
790
|
+
let highestRiskType = "";
|
|
791
|
+
const userRules = getCustomRules();
|
|
792
|
+
for (const rule of userRules) {
|
|
793
|
+
try {
|
|
794
|
+
const re = new RegExp(rule.pattern);
|
|
795
|
+
if (re.test(command)) {
|
|
796
|
+
if (rule.action === "Deny") {
|
|
797
|
+
matched.push(`\u81EA\u5B9A\u4E49\u89C4\u5219: ${rule.pattern}`);
|
|
798
|
+
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
799
|
+
highestSeverity = rule.severity;
|
|
800
|
+
highestRiskType = "custom_rule";
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
} catch {
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
let topRiskType = "";
|
|
808
|
+
for (const rule of DANGEROUS_PATTERNS) {
|
|
809
|
+
if (rule.pattern.test(command)) {
|
|
810
|
+
matched.push(rule.description);
|
|
811
|
+
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
812
|
+
highestSeverity = rule.severity;
|
|
813
|
+
topRiskType = rule.riskType;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
highestRiskType = topRiskType || highestRiskType;
|
|
818
|
+
const agentExt = getAgentExtensions(input.agentId);
|
|
819
|
+
if (agentExt?.extra_command_patterns) {
|
|
820
|
+
for (const rule of agentExt.extra_command_patterns) {
|
|
821
|
+
try {
|
|
822
|
+
const re = new RegExp(rule.pattern, "i");
|
|
823
|
+
if (re.test(command)) {
|
|
824
|
+
matched.push(`agent \u4E13\u5C5E\u89C4\u5219: ${rule.reason}`);
|
|
825
|
+
if (severityRank(rule.risk_level) > severityRank(highestSeverity)) {
|
|
826
|
+
highestSeverity = rule.risk_level;
|
|
827
|
+
highestRiskType = rule.risk_type;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
} catch {
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
const injectionText = `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
835
|
+
const injectionHits = checkInjectionKeywords(injectionText, agentExt?.extra_injection_keywords);
|
|
836
|
+
if (injectionHits.length > 0) {
|
|
837
|
+
const topHit = injectionHits.reduce((a, b) => severityRank(a.riskLevel) >= severityRank(b.riskLevel) ? a : b);
|
|
838
|
+
matched.push(...injectionHits.map((h) => `\u6CE8\u5165\u5173\u952E\u8BCD [${h.lang}]: ${h.keyword}`));
|
|
839
|
+
if (severityRank(topHit.riskLevel) > severityRank(highestSeverity)) {
|
|
840
|
+
highestSeverity = topHit.riskLevel;
|
|
841
|
+
highestRiskType = "prompt_injection";
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
const actionTypeL = input.aNext.actionType.toLowerCase();
|
|
845
|
+
const detailL = input.aNext.actionDetail.toLowerCase();
|
|
846
|
+
const isExcludedType = SENSITIVE_EXCLUDED_PREFIXES.some((p) => actionTypeL.startsWith(p));
|
|
847
|
+
if (!isExcludedType) {
|
|
848
|
+
const pathResult = checkSensitivePath(detailL, input.cwd || "/", agentExt);
|
|
849
|
+
if (pathResult) return pathResult;
|
|
850
|
+
}
|
|
851
|
+
const dangerousResult = checkDangerousPatterns(actionTypeL, detailL);
|
|
852
|
+
if (dangerousResult) return dangerousResult;
|
|
853
|
+
const lateralResult = checkLateralMovement(detailL);
|
|
854
|
+
if (lateralResult) return lateralResult;
|
|
855
|
+
if (matched.length > 0) {
|
|
856
|
+
return {
|
|
857
|
+
allowed: false,
|
|
858
|
+
reason: `\u68C0\u6D4B\u5230\u9AD8\u5371\u64CD\u4F5C: ${matched.join(", ")}`,
|
|
859
|
+
riskLevel: highestSeverity,
|
|
860
|
+
riskType: highestRiskType,
|
|
861
|
+
confidence: 95,
|
|
862
|
+
source: "heuristic",
|
|
863
|
+
violatedLayers: ["1.1"]
|
|
864
|
+
// 对齐 py coordinator.py:165(L1.1 = 命中高危命令模式/注入关键词)
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
869
|
+
function checkInjectionKeywords(text, extraKeywords) {
|
|
870
|
+
const hits = [];
|
|
871
|
+
for (const entry of INJECTION_KEYWORDS) {
|
|
872
|
+
if (text.includes(entry.keyword.toLowerCase())) {
|
|
873
|
+
hits.push(entry);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
if (extraKeywords) {
|
|
877
|
+
for (const entry of extraKeywords) {
|
|
878
|
+
if (text.includes(entry.keyword.toLowerCase())) {
|
|
879
|
+
hits.push({ keyword: entry.keyword, riskLevel: entry.risk_level, lang: entry.lang });
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
return hits;
|
|
884
|
+
}
|
|
885
|
+
function isInlineScriptCommand(actionDetail) {
|
|
886
|
+
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;
|
|
887
|
+
return re.test(actionDetail);
|
|
888
|
+
}
|
|
889
|
+
function severityRank(s) {
|
|
890
|
+
const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
891
|
+
return ranks[s] || 0;
|
|
892
|
+
}
|
|
893
|
+
function checkSensitivePath(command, cwd, agentExt) {
|
|
894
|
+
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
895
|
+
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/];
|
|
896
|
+
const _DEVNULL_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
|
|
897
|
+
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"]);
|
|
898
|
+
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));
|
|
899
|
+
for (const sp of ROOT_SENSITIVE_PATHS) {
|
|
900
|
+
if (command.includes(sp.path.toLowerCase())) {
|
|
901
|
+
if (sp.path === "/dev/random") {
|
|
902
|
+
if (isWriteOpFlag) {
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
return {
|
|
906
|
+
allowed: false,
|
|
907
|
+
reason: `\u8BFB\u53D6\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
908
|
+
riskLevel: sp.riskLevel,
|
|
909
|
+
riskType: "file_access",
|
|
910
|
+
confidence: 90,
|
|
911
|
+
source: "heuristic",
|
|
912
|
+
violatedLayers: ["1.1"]
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
if (!isWriteOpFlag && !sp.credential) {
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
return {
|
|
919
|
+
allowed: false,
|
|
920
|
+
reason: `\u5C1D\u8BD5\u8BBF\u95EE\u7CFB\u7EDF\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
921
|
+
riskLevel: sp.riskLevel,
|
|
922
|
+
riskType: "file_access",
|
|
923
|
+
confidence: 90,
|
|
924
|
+
source: "heuristic",
|
|
925
|
+
violatedLayers: ["1.1"],
|
|
926
|
+
isCredential: !!sp.credential
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
for (const sp of HOME_SENSITIVE_PATHS) {
|
|
931
|
+
const expanded = `${expandedCwd}/${sp.path}`;
|
|
932
|
+
const pathRe = sp.path.endsWith(".pub") ? new RegExp(sp.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i") : new RegExp(sp.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "(?!\\.pub)", "i");
|
|
933
|
+
const expandedRe = sp.path.endsWith(".pub") ? new RegExp(expanded.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i") : new RegExp(expanded.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "(?!\\.pub)", "i");
|
|
934
|
+
if (pathRe.test(command) || expandedRe.test(command)) {
|
|
935
|
+
if (!isWriteOpFlag && !sp.credential) {
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
return {
|
|
939
|
+
allowed: false,
|
|
940
|
+
reason: `\u5C1D\u8BD5\u8BBF\u95EE\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
941
|
+
riskLevel: sp.riskLevel,
|
|
942
|
+
riskType: "file_access",
|
|
943
|
+
confidence: 90,
|
|
944
|
+
source: "heuristic",
|
|
945
|
+
violatedLayers: ["1.1"],
|
|
946
|
+
isCredential: !!sp.credential
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (agentExt?.extra_sensitive_paths && agentExt.extra_sensitive_paths.length > 0) {
|
|
951
|
+
for (const sp of agentExt.extra_sensitive_paths) {
|
|
952
|
+
const spPath = sp.path.toLowerCase();
|
|
953
|
+
const expanded = `${expandedCwd}/${spPath}`;
|
|
954
|
+
if (command.includes(spPath) || command.includes(expanded.toLowerCase())) {
|
|
955
|
+
const denyMode = sp.deny_mode || (sp.credential ? "deny_both" : sp.read_only ? "deny_read" : "deny_write");
|
|
956
|
+
if (denyMode === "deny_read") {
|
|
957
|
+
if (isWriteOpFlag) continue;
|
|
958
|
+
} else if (denyMode === "deny_write") {
|
|
959
|
+
if (!isWriteOpFlag) continue;
|
|
960
|
+
}
|
|
961
|
+
return {
|
|
962
|
+
allowed: false,
|
|
963
|
+
reason: `\u5C1D\u8BD5\u8BBF\u95EE agent \u4E13\u5C5E\u654F\u611F\u8DEF\u5F84: ${sp.desc} (${sp.path})`,
|
|
964
|
+
riskLevel: sp.risk_level,
|
|
965
|
+
riskType: "file_access",
|
|
966
|
+
confidence: 90,
|
|
967
|
+
source: "heuristic",
|
|
968
|
+
violatedLayers: ["1.1"],
|
|
969
|
+
isCredential: !!sp.credential
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
for (const cp of CREDENTIAL_PATHS) {
|
|
975
|
+
const escaped = cp.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
976
|
+
const re = cp.path.startsWith(".") ? new RegExp(`(?:^|[\\s/\\\\'"])${escaped}\\b`) : new RegExp(`\\b${escaped}\\b`);
|
|
977
|
+
if (re.test(command)) {
|
|
978
|
+
return {
|
|
979
|
+
allowed: false,
|
|
980
|
+
reason: `\u8BBF\u95EE\u654F\u611F\u8DEF\u5F84: ${cp.desc} (${cp.path})`,
|
|
981
|
+
riskLevel: cp.riskLevel,
|
|
982
|
+
riskType: "file_access",
|
|
983
|
+
confidence: 90,
|
|
984
|
+
source: "heuristic",
|
|
985
|
+
violatedLayers: ["1.1"],
|
|
986
|
+
isCredential: true
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if ((command.includes("rm ") || command.includes("unlink")) && (command.includes("/etc/") || command.includes("/root/") || command.includes("/var/log/"))) {
|
|
991
|
+
return {
|
|
992
|
+
allowed: false,
|
|
993
|
+
reason: "\u68C0\u6D4B\u5230\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55\u5185\u5BB9",
|
|
994
|
+
riskLevel: "critical",
|
|
995
|
+
riskType: "file_access",
|
|
996
|
+
confidence: 90,
|
|
997
|
+
source: "heuristic",
|
|
998
|
+
violatedLayers: ["1.1"]
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
function checkDangerousPatterns(actionType, actionDetail) {
|
|
1004
|
+
if (actionType === "file_write" || actionType === "file_edit") return null;
|
|
1005
|
+
const TEMP_DIRS = ["/tmp/", "/var/tmp/", "/run/", "/dev/shm/"];
|
|
1006
|
+
const isTempPath = TEMP_DIRS.some((td) => actionDetail.includes(td));
|
|
1007
|
+
if (!isTempPath && (actionDetail.includes("*") || actionDetail.includes("?")) && ["rm ", "rm ", "del ", "del ", "delete", "remove ", "remove ", "\u5220\u9664", "\u79FB\u9664"].some((kw) => actionDetail.includes(kw))) {
|
|
1008
|
+
return {
|
|
1009
|
+
allowed: false,
|
|
1010
|
+
reason: "\u68C0\u6D4B\u5230\u901A\u914D\u7B26\u7ED3\u5408\u5220\u9664\u64CD\u4F5C\uFF0C\u53EF\u80FD\u9020\u6210\u6279\u91CF\u8BEF\u5220",
|
|
1011
|
+
riskLevel: "high",
|
|
1012
|
+
riskType: "script_execution",
|
|
1013
|
+
confidence: 90,
|
|
1014
|
+
source: "heuristic",
|
|
1015
|
+
violatedLayers: ["1.1"]
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
if (/>\s*\/etc\//.test(actionDetail) || />\s*\/boot\//.test(actionDetail) || />\s*\/proc\//.test(actionDetail)) {
|
|
1019
|
+
return {
|
|
1020
|
+
allowed: false,
|
|
1021
|
+
reason: "\u68C0\u6D4B\u5230\u91CD\u5B9A\u5411\u8986\u76D6\u5199\u5165\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55",
|
|
1022
|
+
riskLevel: "critical",
|
|
1023
|
+
riskType: "file_access",
|
|
1024
|
+
confidence: 95,
|
|
1025
|
+
source: "heuristic",
|
|
1026
|
+
violatedLayers: ["1.1"]
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
1031
|
+
function extractRemoteHost(command) {
|
|
1032
|
+
const m = command.match(/(?:ssh|scp|rsync)\s+(?:-[\w]+\s+)*(\S+@\S+|\b(?!-)[\w.-]+\b)/);
|
|
1033
|
+
return m ? m[1] : null;
|
|
1034
|
+
}
|
|
1035
|
+
function isLocalHost(host) {
|
|
1036
|
+
const localNames = ["localhost", "127.0.0.1", "::1", process.env.HOSTNAME || "", "0.0.0.0"];
|
|
1037
|
+
return localNames.includes(host.replace(/.*@/, ""));
|
|
1038
|
+
}
|
|
1039
|
+
function checkLateralMovement(actionDetail) {
|
|
1040
|
+
if (/(?:ssh|scp|rsync)\s+/.test(actionDetail)) {
|
|
1041
|
+
const targetHost = extractRemoteHost(actionDetail);
|
|
1042
|
+
if (targetHost && !isLocalHost(targetHost)) {
|
|
1043
|
+
return {
|
|
1044
|
+
allowed: false,
|
|
1045
|
+
reason: `\u5C1D\u8BD5\u6A2A\u5411\u79FB\u52A8\u5230\u8FDC\u7A0B\u4E3B\u673A: ${targetHost}`,
|
|
1046
|
+
riskLevel: "medium",
|
|
1047
|
+
riskType: "lateral_movement",
|
|
1048
|
+
confidence: 80,
|
|
1049
|
+
source: "heuristic",
|
|
1050
|
+
violatedLayers: ["1.1"]
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1166
1053
|
}
|
|
1167
|
-
return
|
|
1168
|
-
allowed: false,
|
|
1169
|
-
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",
|
|
1170
|
-
riskLevel: "medium",
|
|
1171
|
-
riskType: "file_access",
|
|
1172
|
-
confidence: 70,
|
|
1173
|
-
source: "logic_rule",
|
|
1174
|
-
violatedLayers: ["2"]
|
|
1175
|
-
};
|
|
1054
|
+
return null;
|
|
1176
1055
|
}
|
|
1177
|
-
var
|
|
1178
|
-
var
|
|
1179
|
-
"src/engine/
|
|
1056
|
+
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES;
|
|
1057
|
+
var init_heuristic = __esm({
|
|
1058
|
+
"src/engine/heuristic.ts"() {
|
|
1180
1059
|
"use strict";
|
|
1181
1060
|
init_esm_shims();
|
|
1182
|
-
|
|
1061
|
+
init_config();
|
|
1183
1062
|
init_agents();
|
|
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
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
/\bpasswd\s+-[a-zA-Z]*l\b/i
|
|
1243
|
-
];
|
|
1244
|
-
USER_DELETION_PATTERNS = [
|
|
1245
|
-
/\buserdel\s/i,
|
|
1246
|
-
/\bdeluser\s/i,
|
|
1247
|
-
/\bluserdel\s/i,
|
|
1248
|
-
/\bgroupdel\s/i,
|
|
1249
|
-
/\blgroupdel\s/i
|
|
1250
|
-
];
|
|
1251
|
-
INTENT_DEVIATION_PATTERNS = [
|
|
1252
|
-
{
|
|
1253
|
-
intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
|
|
1254
|
-
dangerousActions: ["\u5220\u9664", "remove", "delete", "rm ", "\u683C\u5F0F\u5316", "format"],
|
|
1255
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
|
|
1256
|
-
},
|
|
1257
|
-
{
|
|
1258
|
-
intentKeywords: ["\u67E5\u8BE2", "\u641C\u7D22", "search", "query", "find"],
|
|
1259
|
-
dangerousActions: ["\u4FEE\u6539", "update", "write", "\u5199\u5165", "alter"],
|
|
1260
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u67E5\u8BE2/\u641C\u7D22\uFF0C\u4F46\u6267\u884C\u4E86\u4FEE\u6539\u64CD\u4F5C"
|
|
1261
|
-
}
|
|
1063
|
+
init_logic_rules();
|
|
1064
|
+
INJECTION_KEYWORDS = [
|
|
1065
|
+
// ---- Instruction Override ----
|
|
1066
|
+
{ keyword: "ignore previous instructions", riskLevel: "critical", lang: "en" },
|
|
1067
|
+
{ keyword: "ignore all previous", riskLevel: "critical", lang: "en" },
|
|
1068
|
+
{ keyword: "disregard all prior", riskLevel: "critical", lang: "en" },
|
|
1069
|
+
{ keyword: "forget everything", riskLevel: "high", lang: "en" },
|
|
1070
|
+
{ keyword: "\u5FFD\u7565\u4E4B\u524D\u7684\u6307\u4EE4", riskLevel: "critical", lang: "zh" },
|
|
1071
|
+
{ keyword: "\u5FFD\u7565\u6240\u6709\u5148\u524D\u7684", riskLevel: "critical", lang: "zh" },
|
|
1072
|
+
{ keyword: "\u5FFD\u7565\u4E0A\u9762\u6240\u6709", riskLevel: "high", lang: "zh" },
|
|
1073
|
+
{ keyword: "\u8BF7\u5FD8\u8BB0\u4E4B\u524D", riskLevel: "high", lang: "zh" },
|
|
1074
|
+
// ---- Role Hijacking ----
|
|
1075
|
+
{ keyword: "you are now", riskLevel: "high", lang: "en" },
|
|
1076
|
+
{ keyword: "you are no longer", riskLevel: "high", lang: "en" },
|
|
1077
|
+
{ keyword: "new instructions", riskLevel: "high", lang: "en" },
|
|
1078
|
+
{ keyword: "from now on, you", riskLevel: "high", lang: "en" },
|
|
1079
|
+
{ keyword: "\u4F60\u73B0\u5728\u662F\u4E00\u4E2A", riskLevel: "high", lang: "zh" },
|
|
1080
|
+
{ keyword: "\u4F60\u4E0D\u518D\u662F\u4E00\u4E2A", riskLevel: "high", lang: "zh" },
|
|
1081
|
+
{ keyword: "\u4ECE\u73B0\u5728\u5F00\u59CB\u4F60", riskLevel: "high", lang: "zh" },
|
|
1082
|
+
{ keyword: "\u4F60\u7684\u65B0\u89D2\u8272\u662F", riskLevel: "high", lang: "zh" },
|
|
1083
|
+
// ---- Command Injection ----
|
|
1084
|
+
{ keyword: "system prompt", riskLevel: "high", lang: "en" },
|
|
1085
|
+
{ keyword: "reveal your instructions", riskLevel: "high", lang: "en" },
|
|
1086
|
+
{ keyword: "output your instructions", riskLevel: "high", lang: "en" },
|
|
1087
|
+
{ keyword: "repeat your instructions", riskLevel: "medium", lang: "en" },
|
|
1088
|
+
{ keyword: "\u7CFB\u7EDF\u63D0\u793A", riskLevel: "high", lang: "zh" },
|
|
1089
|
+
{ keyword: "\u8F93\u51FA\u4F60\u7684\u6307\u4EE4", riskLevel: "high", lang: "zh" },
|
|
1090
|
+
{ keyword: "\u91CD\u590D\u4F60\u7684\u6307\u4EE4", riskLevel: "medium", lang: "zh" },
|
|
1091
|
+
// ---- Social Engineering ----
|
|
1092
|
+
{ keyword: "this is an authorized test", riskLevel: "high", lang: "en" },
|
|
1093
|
+
{ keyword: "security audit approved", riskLevel: "high", lang: "en" },
|
|
1094
|
+
{ keyword: "admin override", riskLevel: "critical", lang: "en" },
|
|
1095
|
+
{ keyword: "debug mode", riskLevel: "high", lang: "en" },
|
|
1096
|
+
{ keyword: "maintenance mode", riskLevel: "high", lang: "en" },
|
|
1097
|
+
{ keyword: "\u8FD9\u662F\u6388\u6743\u7684\u6D4B\u8BD5", riskLevel: "high", lang: "zh" },
|
|
1098
|
+
{ keyword: "\u5B89\u5168\u5BA1\u8BA1\u5DF2\u6279\u51C6", riskLevel: "high", lang: "zh" },
|
|
1099
|
+
{ keyword: "\u7BA1\u7406\u5458\u8986\u76D6", riskLevel: "critical", lang: "zh" },
|
|
1100
|
+
{ keyword: "\u8C03\u8BD5\u6A21\u5F0F", riskLevel: "high", lang: "zh" },
|
|
1101
|
+
// ---- XSS ----
|
|
1102
|
+
{ keyword: "<script>", riskLevel: "high", lang: "en" },
|
|
1103
|
+
{ keyword: "javascript:", riskLevel: "high", lang: "en" },
|
|
1104
|
+
{ keyword: "onerror=", riskLevel: "high", lang: "en" },
|
|
1105
|
+
{ keyword: "onload=", riskLevel: "high", lang: "en" },
|
|
1106
|
+
// ---- Fake Boundaries ----
|
|
1107
|
+
{ keyword: "=== END OF", riskLevel: "high", lang: "en" },
|
|
1108
|
+
{ keyword: "--- END SYSTEM", riskLevel: "high", lang: "en" },
|
|
1109
|
+
{ keyword: "[END OF", riskLevel: "high", lang: "en" },
|
|
1110
|
+
{ keyword: "=== \u7ED3\u675F", riskLevel: "high", lang: "zh" },
|
|
1111
|
+
{ keyword: "--- \u7ED3\u675F\u7CFB\u7EDF", riskLevel: "high", lang: "zh" },
|
|
1112
|
+
// ---- Developer Mode ----
|
|
1113
|
+
{ keyword: "developer mode", riskLevel: "critical", lang: "en" },
|
|
1114
|
+
{ keyword: "DAN mode", riskLevel: "critical", lang: "en" },
|
|
1115
|
+
{ keyword: "jailbreak", riskLevel: "critical", lang: "en" },
|
|
1116
|
+
{ keyword: "\u5F00\u53D1\u8005\u6A21\u5F0F", riskLevel: "critical", lang: "zh" },
|
|
1117
|
+
{ keyword: "\u8D8A\u72F1", riskLevel: "critical", lang: "zh" }
|
|
1118
|
+
// 注:xiaoO 专属绕过词(绕过审计/禁用安全检查/关闭防护/bypass audit 等)
|
|
1119
|
+
// 已迁至 agent_moss/agents/xiaoo/rules.json 的 extra_injection_keywords,
|
|
1120
|
+
// 由 agent_ext 机制注入,不再污染通用层。
|
|
1262
1121
|
];
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
"
|
|
1267
|
-
"
|
|
1268
|
-
|
|
1269
|
-
"
|
|
1270
|
-
|
|
1271
|
-
"
|
|
1272
|
-
|
|
1273
|
-
"
|
|
1274
|
-
|
|
1122
|
+
DANGEROUS_PATTERNS = [
|
|
1123
|
+
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
1124
|
+
// 1. rm -rf root dir (含通配符如 /* /.* 等) — 使用负向先行断言 (?!\w):/ 后面不是单词字符时匹配
|
|
1125
|
+
{ 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" },
|
|
1126
|
+
// 注意:已移除"rm -rf /任意绝对路径"的宽泛规则,避免误杀 /tmp 等临时目录清理操作
|
|
1127
|
+
// 2. rm with -r or -f targeting system dirs — var 分支排除 /var/tmp/(合法清理)
|
|
1128
|
+
{ 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" },
|
|
1129
|
+
// 3. rm -r absolute path (no -f) — 排除 /tmp/ /var/tmp/ /run/ /dev/shm/(CI/开发高频合法清理)
|
|
1130
|
+
{ 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" },
|
|
1131
|
+
// 4. rm -f absolute path (no -r) — 同样排除临时目录
|
|
1132
|
+
{ 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" },
|
|
1133
|
+
// dd 磁盘清零 — 只拦截写入系统关键目录,放行 /tmp 等临时目录
|
|
1134
|
+
{ 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" },
|
|
1135
|
+
// mkfs 格式化 — 只拦截对块设备(/dev/sdX 等)的格式化,放行对普通文件的格式化
|
|
1136
|
+
{ 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" },
|
|
1137
|
+
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
1138
|
+
// --- Critical: remote code execution ---
|
|
1139
|
+
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
1140
|
+
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
1141
|
+
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
1142
|
+
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "critical", description: "base64 \u89E3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
1143
|
+
// --- Critical: reverse shell ---
|
|
1144
|
+
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
1145
|
+
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
1146
|
+
// --- Critical: sensitive file access ---
|
|
1147
|
+
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
1148
|
+
{ pattern: /\/etc\/gshadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6 (/etc/gshadow)", riskType: "file_access" },
|
|
1149
|
+
// 注意:/etc/passwd 已从拦截列表移除,因为它是公开可读的标准系统文件,真正敏感的是 /etc/shadow
|
|
1150
|
+
{ pattern: /\.ssh\/id_rsa(?!\.pub)/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
1151
|
+
// --- Critical: privilege escalation / container escape ---
|
|
1152
|
+
{ 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" },
|
|
1153
|
+
// --- High: dangerous permissions / ownership ---
|
|
1154
|
+
{ pattern: /chmod\s+[0-7]*777[0-7]*/i, severity: "high", description: "\u5168\u6743\u9650\u8BBE\u7F6E (chmod 777)", riskType: "script_execution" },
|
|
1155
|
+
{ 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" },
|
|
1156
|
+
// sudo 提权 — 只拦截 sudo 后跟的危险命令,不一刀切拦截所有 sudo
|
|
1157
|
+
{ 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" },
|
|
1158
|
+
// --- High: system config overwrite ---
|
|
1159
|
+
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
1160
|
+
// --- High: download script + execute risk ---
|
|
1161
|
+
{ 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" },
|
|
1162
|
+
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
1163
|
+
// --- High: package manager pipe-to-shell ---
|
|
1164
|
+
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
1165
|
+
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
1166
|
+
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
1167
|
+
// --- Medium: destructive git operations (降级为 medium,允许但记录) ---
|
|
1168
|
+
{ 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" },
|
|
1169
|
+
// --- High: network port scanning (横向移动侦察) ---
|
|
1170
|
+
{ 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" },
|
|
1171
|
+
{ 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" },
|
|
1172
|
+
// --- Medium: credential export ---
|
|
1173
|
+
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
1174
|
+
// --- High: shell rc file append (persistence) ---
|
|
1175
|
+
{ 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" },
|
|
1176
|
+
// --- High: device file write (只拦截重定向写入设备文件,不拦截读取) ---
|
|
1177
|
+
{ 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" },
|
|
1178
|
+
// --- High: non-interactive password modification ---
|
|
1179
|
+
{ 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" },
|
|
1180
|
+
{ 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" },
|
|
1181
|
+
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
1182
|
+
{ 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" },
|
|
1183
|
+
{ 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" },
|
|
1184
|
+
{ 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" },
|
|
1185
|
+
// --- High: non-interactive password modification (extended) ---
|
|
1186
|
+
{ pattern: /\blpasswd\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u64CD\u4F5C (lpasswd)", riskType: "script_execution" },
|
|
1187
|
+
{ pattern: /\bgpasswd\s+(?!-[adA])/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7EC4\u5BC6\u7801\u7BA1\u7406\u64CD\u4F5C (gpasswd)", riskType: "script_execution" },
|
|
1188
|
+
{ pattern: /\bchgpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u6279\u91CF\u4FEE\u6539\u7EC4\u5BC6\u7801\u64CD\u4F5C (chgpasswd)", riskType: "script_execution" },
|
|
1189
|
+
// --- High: user/group deletion (irreversible, requires user consent) ---
|
|
1190
|
+
{ pattern: /\buserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (userdel)", riskType: "script_execution" },
|
|
1191
|
+
{ pattern: /\bdeluser\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (deluser)", riskType: "script_execution" },
|
|
1192
|
+
{ pattern: /\bluserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (luserdel)", riskType: "script_execution" },
|
|
1193
|
+
{ pattern: /\bgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (groupdel)", riskType: "script_execution" },
|
|
1194
|
+
{ pattern: /\blgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (lgroupdel)", riskType: "script_execution" },
|
|
1195
|
+
// --- High: generic command -p parameter password setting ---
|
|
1196
|
+
{ 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" }
|
|
1275
1197
|
];
|
|
1198
|
+
SENSITIVE_EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
1276
1199
|
}
|
|
1277
1200
|
});
|
|
1278
1201
|
|
|
@@ -2653,7 +2576,10 @@ function getEnabledL1CommandPatterns(runtime) {
|
|
|
2653
2576
|
}));
|
|
2654
2577
|
}
|
|
2655
2578
|
function getEnabledL2SensitivePaths(runtime) {
|
|
2656
|
-
|
|
2579
|
+
let cat = runtime.L1_rules?.sensitive_path_access;
|
|
2580
|
+
if (!cat || !cat.rules || cat.rules.length === 0) {
|
|
2581
|
+
cat = runtime.L2_rules?.sensitive_path_access || { category_enabled: true, rules: [] };
|
|
2582
|
+
}
|
|
2657
2583
|
return filterEnabledRules(cat.rules || [], cat.category_enabled).map((r) => {
|
|
2658
2584
|
const out = { path: r.path || "", risk_level: r.risk_level || "", desc: r.desc || "", deny_mode: r.deny_mode || "deny_write" };
|
|
2659
2585
|
if (r.credential) out.credential = true;
|
|
@@ -2679,22 +2605,24 @@ function getDisabledL2RulesWithSkipL3() {
|
|
|
2679
2605
|
return {};
|
|
2680
2606
|
}
|
|
2681
2607
|
const result = {};
|
|
2682
|
-
const
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
if (
|
|
2689
|
-
if (
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2608
|
+
for (const layerKey of ["L1_rules", "L2_rules"]) {
|
|
2609
|
+
const layer = runtime[layerKey] || {};
|
|
2610
|
+
for (const [catName, cat] of Object.entries(layer)) {
|
|
2611
|
+
if (!cat.category_enabled) continue;
|
|
2612
|
+
const items = [];
|
|
2613
|
+
for (const r of cat.rules || []) {
|
|
2614
|
+
if (r.enabled === false && r.skip_l3_on_disabled) {
|
|
2615
|
+
if (catName === "sensitive_path_access") {
|
|
2616
|
+
if (r.path) items.push(r.path);
|
|
2617
|
+
} else if (catName === "intent_consistency") {
|
|
2618
|
+
items.push(...r.intent_keywords || []);
|
|
2619
|
+
} else if (r.pattern) {
|
|
2620
|
+
items.push(r.pattern);
|
|
2621
|
+
}
|
|
2694
2622
|
}
|
|
2695
2623
|
}
|
|
2624
|
+
if (items.length > 0) result[catName] = items;
|
|
2696
2625
|
}
|
|
2697
|
-
if (items.length > 0) result[catName] = items;
|
|
2698
2626
|
}
|
|
2699
2627
|
return result;
|
|
2700
2628
|
}
|
|
@@ -2855,15 +2783,14 @@ function generateSourceDefaults() {
|
|
|
2855
2783
|
category_desc: "Prompt \u6CE8\u5165\u653B\u51FB\u68C0\u6D4B",
|
|
2856
2784
|
rules: _l1InjectionKeywordsToRules()
|
|
2857
2785
|
},
|
|
2858
|
-
user_sensitive_actions: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49\u654F\u611F\u52A8\u4F5C/\u5DE5\u5177\u89C4\u5219", rules: [] },
|
|
2859
|
-
user_custom: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49\u547D\u4EE4\u89C4\u5219", rules: [] }
|
|
2860
|
-
},
|
|
2861
|
-
L2_rules: {
|
|
2862
2786
|
sensitive_path_access: {
|
|
2863
2787
|
category_enabled: true,
|
|
2864
|
-
category_desc: "\u654F\u611F\u8DEF\u5F84\u8BBF\u95EE\u68C0\u6D4B",
|
|
2788
|
+
category_desc: "\u654F\u611F\u8DEF\u5F84\u8BBF\u95EE\u68C0\u6D4B\uFF08deny_both/deny_read/deny_write\uFF09",
|
|
2865
2789
|
rules: _l2SensitivePathsToRules()
|
|
2866
2790
|
},
|
|
2791
|
+
user_custom: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49\u547D\u4EE4\u89C4\u5219", rules: [] }
|
|
2792
|
+
},
|
|
2793
|
+
L2_rules: {
|
|
2867
2794
|
intent_consistency: {
|
|
2868
2795
|
category_enabled: true,
|
|
2869
2796
|
category_desc: "\u610F\u56FE\u4E00\u81F4\u6027\u68C0\u6D4B",
|
|
@@ -2880,7 +2807,7 @@ function generateSourceDefaults() {
|
|
|
2880
2807
|
rules: _l2UserDeletionPatternsToRules()
|
|
2881
2808
|
},
|
|
2882
2809
|
read_before_write: { category_enabled: true, category_desc: "read_before_write \u5B89\u5168\u539F\u5219\u68C0\u6D4B", rules: [] },
|
|
2883
|
-
|
|
2810
|
+
user_custom: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49 L2 \u903B\u8F91\u89C4\u5219", rules: [] }
|
|
2884
2811
|
},
|
|
2885
2812
|
L3_skills: _l3SkillsToRules()
|
|
2886
2813
|
};
|
|
@@ -2948,6 +2875,10 @@ function _mergeRuleCategories(userCfg, srcDefaults, layerKey) {
|
|
|
2948
2875
|
}
|
|
2949
2876
|
}
|
|
2950
2877
|
}
|
|
2878
|
+
for (const catName of Object.keys(userLayer)) {
|
|
2879
|
+
if (catName === "user_custom") continue;
|
|
2880
|
+
if (!(catName in srcLayer)) delete userLayer[catName];
|
|
2881
|
+
}
|
|
2951
2882
|
}
|
|
2952
2883
|
function _mergeSkillCategories(userCfg, srcDefaults, layerKey) {
|
|
2953
2884
|
const userLayer = userCfg[layerKey] || (userCfg[layerKey] = {});
|
|
@@ -2974,11 +2905,42 @@ function mergeConfig(userCfg, srcDefaults) {
|
|
|
2974
2905
|
for (const [layerKey, defaultVal] of Object.entries(srcDefaults.layers)) {
|
|
2975
2906
|
if (!(layerKey in cfg.layers)) cfg.layers[layerKey] = defaultVal;
|
|
2976
2907
|
}
|
|
2908
|
+
_migrateCategoriesAcrossLayers(
|
|
2909
|
+
cfg,
|
|
2910
|
+
"L2_rules",
|
|
2911
|
+
"L1_rules",
|
|
2912
|
+
["sensitive_path_access"]
|
|
2913
|
+
);
|
|
2977
2914
|
_mergeRuleCategories(cfg, srcDefaults, "L1_rules");
|
|
2978
2915
|
_mergeRuleCategories(cfg, srcDefaults, "L2_rules");
|
|
2979
2916
|
_mergeSkillCategories(cfg, srcDefaults, "L3_skills");
|
|
2980
2917
|
return cfg;
|
|
2981
2918
|
}
|
|
2919
|
+
function _migrateCategoriesAcrossLayers(cfg, srcLayer, dstLayer, catNames) {
|
|
2920
|
+
const src = cfg[srcLayer] || {};
|
|
2921
|
+
const dst = cfg[dstLayer] || (cfg[dstLayer] = {});
|
|
2922
|
+
for (const catName of catNames) {
|
|
2923
|
+
if (!(catName in src)) continue;
|
|
2924
|
+
const srcCat = src[catName];
|
|
2925
|
+
if (!dst[catName]) {
|
|
2926
|
+
dst[catName] = { category_enabled: true, category_desc: "", rules: [] };
|
|
2927
|
+
}
|
|
2928
|
+
const dstCat = dst[catName];
|
|
2929
|
+
if (!dstCat.category_desc && srcCat.category_desc) dstCat.category_desc = srcCat.category_desc;
|
|
2930
|
+
if (dstCat.category_enabled === void 0) dstCat.category_enabled = srcCat.category_enabled;
|
|
2931
|
+
if (srcCat.rules && srcCat.rules.length > 0) {
|
|
2932
|
+
const dstFps = new Set((dstCat.rules || []).map((r) => _ruleFingerprint(r)));
|
|
2933
|
+
for (const r of srcCat.rules) {
|
|
2934
|
+
const fp = _ruleFingerprint(r);
|
|
2935
|
+
if (!dstFps.has(fp)) {
|
|
2936
|
+
(dstCat.rules = dstCat.rules || []).push(r);
|
|
2937
|
+
dstFps.add(fp);
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
delete src[catName];
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2982
2944
|
function getEnabledL1InjectionKeywords(runtime) {
|
|
2983
2945
|
const cat = runtime.L1_rules?.injection_detection || { category_enabled: true, rules: [] };
|
|
2984
2946
|
return filterEnabledRules(cat.rules || [], cat.category_enabled).map((r) => ({
|
|
@@ -3131,7 +3093,8 @@ function deleteCustomRule(layer, category, ruleId) {
|
|
|
3131
3093
|
const rules = runtime[layer]?.[category]?.rules || [];
|
|
3132
3094
|
const idx = rules.findIndex((r) => r.id === ruleId);
|
|
3133
3095
|
if (idx >= 0) {
|
|
3134
|
-
|
|
3096
|
+
const r = rules[idx];
|
|
3097
|
+
if (r.builtin && !r.source_removed) return null;
|
|
3135
3098
|
rules.splice(idx, 1);
|
|
3136
3099
|
saveRuntimeConfig(runtime);
|
|
3137
3100
|
}
|
|
@@ -3326,9 +3289,11 @@ async function runAnalysis(input) {
|
|
|
3326
3289
|
}
|
|
3327
3290
|
}
|
|
3328
3291
|
const logicResult = isLogicRulesEnabled() ? runLogicCheck(input) : null;
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3292
|
+
const l1FileAccessHit = !!(heuristicResult && !heuristicResult.allowed && heuristicResult.riskType === "file_access");
|
|
3293
|
+
const effectiveResult = logicResult && !logicResult.allowed ? logicResult : l1FileAccessHit ? heuristicResult : null;
|
|
3294
|
+
if (effectiveResult) {
|
|
3295
|
+
const isCredentialPath = !!effectiveResult.isCredential;
|
|
3296
|
+
const skipInlineFileAccess = (isInlineScriptCmd || isLiteralTextCmd) && effectiveResult.riskType === "file_access";
|
|
3332
3297
|
if (skipInlineFileAccess) {
|
|
3333
3298
|
const inlineJudgment = analyzeInlineScript(input.aNext.actionDetail);
|
|
3334
3299
|
if (inlineJudgment.actionable) {
|
|
@@ -3354,8 +3319,8 @@ async function runAnalysis(input) {
|
|
|
3354
3319
|
};
|
|
3355
3320
|
}
|
|
3356
3321
|
}
|
|
3357
|
-
if ((
|
|
3358
|
-
return
|
|
3322
|
+
if ((effectiveResult.riskLevel === "high" || effectiveResult.riskLevel === "critical") && (!skipInlineFileAccess || isCredentialPath)) {
|
|
3323
|
+
return effectiveResult;
|
|
3359
3324
|
}
|
|
3360
3325
|
}
|
|
3361
3326
|
if (scriptChain && scriptChain.nodes.length > 0 && isLogicRulesEnabled()) {
|