sema-core 2.0.5 → 2.0.7
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/events/types.d.ts +13 -0
- package/dist/events/types.d.ts.map +1 -1
- package/dist/manager/PermissionManager.d.ts.map +1 -1
- package/dist/manager/PermissionManager.js +66 -88
- package/dist/manager/PermissionManager.js.map +1 -1
- package/dist/manager/StateManager.d.ts +1 -1
- package/dist/manager/StateManager.js +1 -1
- package/dist/prompt/memory.d.ts.map +1 -1
- package/dist/prompt/memory.js +23 -12
- package/dist/prompt/memory.js.map +1 -1
- package/dist/prompt/permission.d.ts +1 -1
- package/dist/prompt/permission.d.ts.map +1 -1
- package/dist/prompt/permission.js +43 -7
- package/dist/prompt/permission.js.map +1 -1
- package/dist/services/api/apiUtil.js +2 -2
- package/dist/services/api/apiUtil.js.map +1 -1
- package/dist/tools/FetchUrl.js +1 -1
- package/dist/tools/FetchUrl.js.map +1 -1
- package/dist/tools/PickOption.d.ts +26 -0
- package/dist/tools/PickOption.d.ts.map +1 -1
- package/dist/tools/PickOption.js +30 -18
- package/dist/tools/PickOption.js.map +1 -1
- package/dist/tools/RunShell.d.ts.map +1 -1
- package/dist/tools/RunShell.js +8 -7
- package/dist/tools/RunShell.js.map +1 -1
- package/dist/util/commands.d.ts +14 -0
- package/dist/util/commands.d.ts.map +1 -1
- package/dist/util/commands.js +115 -4
- package/dist/util/commands.js.map +1 -1
- package/dist/util/commands.test.d.ts +2 -0
- package/dist/util/commands.test.d.ts.map +1 -0
- package/dist/util/commands.test.js +93 -0
- package/dist/util/commands.test.js.map +1 -0
- package/dist/util/fetchSafety.d.ts +11 -0
- package/dist/util/fetchSafety.d.ts.map +1 -0
- package/dist/util/fetchSafety.js +86 -0
- package/dist/util/fetchSafety.js.map +1 -0
- package/dist/util/fetchSafety.test.d.ts +2 -0
- package/dist/util/fetchSafety.test.d.ts.map +1 -0
- package/dist/util/fetchSafety.test.js +44 -0
- package/dist/util/fetchSafety.test.js.map +1 -0
- package/dist/util/fetchUrl.d.ts +1 -1
- package/dist/util/fetchUrl.d.ts.map +1 -1
- package/dist/util/fetchUrl.js +2 -2
- package/dist/util/fetchUrl.js.map +1 -1
- package/dist/util/shellSafety.d.ts +34 -0
- package/dist/util/shellSafety.d.ts.map +1 -0
- package/dist/util/shellSafety.js +122 -0
- package/dist/util/shellSafety.js.map +1 -0
- package/dist/util/shellSafety.test.d.ts +2 -0
- package/dist/util/shellSafety.test.d.ts.map +1 -0
- package/dist/util/shellSafety.test.js +103 -0
- package/dist/util/shellSafety.test.js.map +1 -0
- package/package.json +1 -1
package/dist/util/commands.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.hasCommandInjection = hasCommandInjection;
|
|
4
|
+
exports.stripHeredocBody = stripHeredocBody;
|
|
4
5
|
exports.splitCommand = splitCommand;
|
|
5
6
|
exports.getCommandPrefix = getCommandPrefix;
|
|
6
7
|
const shell_quote_1 = require("shell-quote");
|
|
@@ -10,11 +11,121 @@ const commands_1 = require("../prompt/commands");
|
|
|
10
11
|
const SQ_PLACEHOLDER = '__SQ_PLACEHOLDER__';
|
|
11
12
|
const DQ_PLACEHOLDER = '__DQ_PLACEHOLDER__';
|
|
12
13
|
const BS_PLACEHOLDER = '__BS_PLACEHOLDER__';
|
|
13
|
-
// 命令注入特征:反引号 / $( / 换行 / && / || /
|
|
14
|
-
//
|
|
15
|
-
|
|
14
|
+
// 命令注入特征:反引号 / $( / 换行 / && / || / ;。
|
|
15
|
+
// 但必须区分引号内外——引号里的换行/分号是字面数据(如 echo "多行文本"),不是命令分隔:
|
|
16
|
+
// - 单引号内:全部字面,shell 不做任何解释 → 一律忽略
|
|
17
|
+
// - 双引号内:换行 / ; / && / || 是字面,但 $( 与反引号仍是命令替换 → 仅检出这两者
|
|
18
|
+
// - 引号外:换行 / ; / && / || / $( / 反引号 全部视为注入
|
|
19
|
+
// 反斜杠转义会跳过下一个字符,避免把 \" \' 误判为引号边界。解析始终保守(fail-closed)。
|
|
16
20
|
function hasCommandInjection(command) {
|
|
17
|
-
|
|
21
|
+
let inSingle = false;
|
|
22
|
+
let inDouble = false;
|
|
23
|
+
for (let i = 0; i < command.length; i++) {
|
|
24
|
+
const c = command[i];
|
|
25
|
+
const next = command[i + 1];
|
|
26
|
+
if (inSingle) {
|
|
27
|
+
// 单引号内无转义,仅 ' 结束
|
|
28
|
+
if (c === "'")
|
|
29
|
+
inSingle = false;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (c === '\\') {
|
|
33
|
+
// 引号外或双引号内:反斜杠转义下一个字符,跳过
|
|
34
|
+
i++;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (inDouble) {
|
|
38
|
+
if (c === '`')
|
|
39
|
+
return true;
|
|
40
|
+
if (c === '$' && next === '(')
|
|
41
|
+
return true;
|
|
42
|
+
if (c === '"')
|
|
43
|
+
inDouble = false;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
// 引号外
|
|
47
|
+
if (c === "'") {
|
|
48
|
+
inSingle = true;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (c === '"') {
|
|
52
|
+
inDouble = true;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (c === '`' || c === '\n' || c === ';')
|
|
56
|
+
return true;
|
|
57
|
+
if (c === '$' && next === '(')
|
|
58
|
+
return true;
|
|
59
|
+
if ((c === '&' || c === '|') && next === c)
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// heredoc 起始标记:<< 或 <<-,后跟可选引号包裹的结束符。
|
|
65
|
+
// 不匹配 <<<(here-string,语义不同):<< 后紧跟 < 不是引号也不是标识符首字符,自然落空。
|
|
66
|
+
const HEREDOC_START_RE = /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/g;
|
|
67
|
+
/**
|
|
68
|
+
* 剥离 heredoc 正文,返回仅含"命令骨架"的字符串,供注入检测使用。
|
|
69
|
+
*
|
|
70
|
+
* heredoc 正文是喂给程序的「数据」而非 shell 命令,但底层 shell-quote 不理解 heredoc,
|
|
71
|
+
* 会把正文按 token 打散、换行有时残留,导致 hasCommandInjection 把正文换行误判为命令注入
|
|
72
|
+
* (是否误判还取决于正文里有无 # 注释等,结果不稳定)。本函数在解析前把正文摘掉:
|
|
73
|
+
* - 结束符带引号(<< 'X' / << "X"):正文纯字面,shell 不展开,直接剥离
|
|
74
|
+
* - 结束符不带引号(<< X):shell 会对正文做命令替换,仅当正文不含 $( / 反引号 时才剥离;
|
|
75
|
+
* 含命令替换则保留拦截(返回原命令,让 hasCommandInjection 照常检出)
|
|
76
|
+
*
|
|
77
|
+
* 任何无法可靠解析的情形(多 heredoc 同行、缺结束符等)一律返回原命令(fail-closed,维持现状),
|
|
78
|
+
* 绝不因剥离而放过真注入。
|
|
79
|
+
*/
|
|
80
|
+
function stripHeredocBody(command) {
|
|
81
|
+
if (!command.includes('\n'))
|
|
82
|
+
return command;
|
|
83
|
+
const lines = command.split('\n');
|
|
84
|
+
const out = [];
|
|
85
|
+
let i = 0;
|
|
86
|
+
while (i < lines.length) {
|
|
87
|
+
const line = lines[i];
|
|
88
|
+
const matches = [...line.matchAll(HEREDOC_START_RE)];
|
|
89
|
+
if (matches.length === 0) {
|
|
90
|
+
out.push(line);
|
|
91
|
+
i++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// 同一行多个 heredoc:正文顺序复杂,放弃剥离
|
|
95
|
+
if (matches.length > 1)
|
|
96
|
+
return command;
|
|
97
|
+
const m = matches[0];
|
|
98
|
+
const quoted = m[1] !== '';
|
|
99
|
+
const delim = m[2];
|
|
100
|
+
// 起始行保留,正文从下一行起到独占一行的结束符为止。
|
|
101
|
+
// 结束符匹配忽略两侧空白:真实 shell 对 << 要求结束符顶格(仅 <<- 允许 tab),但调用方/agent
|
|
102
|
+
// 常带缩进。放宽只会让我们更早判定正文边界——结束符之后的内容仍照常做注入检测(更保守,不放过
|
|
103
|
+
// 真注入);带引号正文本就字面、不带引号正文已先扫 $(/反引号,故放宽不削弱安全性。
|
|
104
|
+
out.push(line);
|
|
105
|
+
let j = i + 1;
|
|
106
|
+
const body = [];
|
|
107
|
+
let foundEnd = false;
|
|
108
|
+
for (; j < lines.length; j++) {
|
|
109
|
+
const bodyLine = lines[j];
|
|
110
|
+
if (bodyLine.trim() === delim) {
|
|
111
|
+
foundEnd = true;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
body.push(bodyLine);
|
|
115
|
+
}
|
|
116
|
+
// 没找到结束符(命令被截断等)→ fail-closed
|
|
117
|
+
if (!foundEnd)
|
|
118
|
+
return command;
|
|
119
|
+
// 不带引号且正文含命令替换 → shell 会真执行,保留拦截
|
|
120
|
+
if (!quoted) {
|
|
121
|
+
const bodyText = body.join('\n');
|
|
122
|
+
if (bodyText.includes('$(') || bodyText.includes('`'))
|
|
123
|
+
return command;
|
|
124
|
+
}
|
|
125
|
+
// 剥离正文与结束符行,直接跳到结束符行之后
|
|
126
|
+
i = j + 1;
|
|
127
|
+
}
|
|
128
|
+
return out.join('\n');
|
|
18
129
|
}
|
|
19
130
|
/**
|
|
20
131
|
* 根据shell操作符将命令字符串拆分为单个命令
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/util/commands.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/util/commands.ts"],"names":[],"mappings":";;AAsBA,kDAkCC;AAmBD,4CAsDC;AAKD,oCA+GC;AAED,4CA2DC;AAlTD,6CAAqE;AACrE,uDAAqD;AACrD,uCAA0C;AAC1C,iDAA6F;AAE7F,MAAM,cAAc,GAAG,oBAAoB,CAAA;AAC3C,MAAM,cAAc,GAAG,oBAAoB,CAAA;AAC3C,MAAM,cAAc,GAAG,oBAAoB,CAAA;AAS3C,sCAAsC;AACtC,mDAAmD;AACnD,mCAAmC;AACnC,wDAAwD;AACxD,4CAA4C;AAC5C,uDAAuD;AACvD,SAAgB,mBAAmB,CAAC,OAAe;IACjD,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QACpB,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAE3B,IAAI,QAAQ,EAAE,CAAC;YACb,iBAAiB;YACjB,IAAI,CAAC,KAAK,GAAG;gBAAE,QAAQ,GAAG,KAAK,CAAA;YAC/B,SAAQ;QACV,CAAC;QAED,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACf,yBAAyB;YACzB,CAAC,EAAE,CAAA;YACH,SAAQ;QACV,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAA;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAA;YAC1C,IAAI,CAAC,KAAK,GAAG;gBAAE,QAAQ,GAAG,KAAK,CAAA;YAC/B,SAAQ;QACV,CAAC;QAED,MAAM;QACN,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAAC,QAAQ,GAAG,IAAI,CAAC;YAAC,SAAQ;QAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAAC,QAAQ,GAAG,IAAI,CAAC;YAAC,SAAQ;QAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAA;QACrD,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO,IAAI,CAAA;QAC1C,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;IACzD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,sCAAsC;AACtC,yDAAyD;AACzD,MAAM,gBAAgB,GAAG,2CAA2C,CAAA;AAEpE;;;;;;;;;;;;GAYG;AACH,SAAgB,gBAAgB,CAAC,OAAe;IAC9C,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,OAAO,CAAA;IAE3C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,IAAI,CAAC,GAAG,CAAC,CAAA;IAET,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAA;QACtB,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAA;QAEpD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACd,CAAC,EAAE,CAAA;YACH,SAAQ;QACV,CAAC;QACD,4BAA4B;QAC5B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,OAAO,CAAA;QAEtC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;QACrB,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAA;QAC1B,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAE,CAAA;QAEnB,4BAA4B;QAC5B,6DAA6D;QAC7D,iDAAiD;QACjD,6CAA6C;QAC7C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACd,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACb,MAAM,IAAI,GAAa,EAAE,CAAA;QACzB,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAE,CAAA;YAC1B,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC9B,QAAQ,GAAG,IAAI,CAAA;gBACf,MAAK;YACP,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACrB,CAAC;QAED,8BAA8B;QAC9B,IAAI,CAAC,QAAQ;YAAE,OAAO,OAAO,CAAA;QAE7B,iCAAiC;QACjC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAChC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO,OAAO,CAAA;QACvE,CAAC;QAED,uBAAuB;QACvB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACX,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvB,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,OAAe;IAC1C,MAAM,KAAK,GAAiB,EAAE,CAAA;IAE9B,cAAc;IACd,KAAK,MAAM,IAAI,IAAI,IAAA,mBAAK,EACtB,OAAO;SACJ,UAAU,CAAC,IAAI,EAAE,cAAc,CAAC;SAChC,UAAU,CAAC,GAAG,EAAE,IAAI,cAAc,EAAE,CAAC;SACrC,UAAU,CAAC,GAAG,EAAE,IAAI,cAAc,EAAE,CAAC,EACxC,OAAO,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CACzB,EAAE,CAAC;QACF,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACpE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,IAAI,CAAA;gBACrC,SAAQ;YACV,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClB,CAAC;IAED,eAAe;IACf,MAAM,WAAW,GAAG,KAAK;SACtB,GAAG,CAAC,IAAI,CAAC,EAAE;QACV,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAA;QACb,CAAC;QACD,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;YACtB,OAAO,GAAG,GAAG,IAAI,CAAC,OAAO,CAAA;QAC3B,CAAC;QACD,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC,OAAO,CAAA;QACrB,CAAC;QACD,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC,EAAE,CAAA;QAChB,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAA;IAEvD,gBAAgB;IAChB,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QACzC,OAAO,IAAI;aACR,UAAU,CAAC,GAAG,cAAc,EAAE,EAAE,GAAG,CAAC;aACpC,UAAU,CAAC,GAAG,cAAc,EAAE,EAAE,GAAG,CAAC;aACpC,UAAU,CAAC,GAAG,cAAc,EAAE,EAAE,IAAI,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;IAEF,YAAY;IACZ,MAAM,YAAY,GAAa,EAAE,CAAA;IACjC,IAAI,cAAc,GAAkB,IAAI,CAAA;IACxC,IAAI,wBAAwB,GAAG,CAAC,CAAA;IAEhC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QAClC,cAAc,GAAG,cAAc;YAC7B,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAC5B,CAAC,CAAC,GAAG,cAAc,GAAG,IAAI,EAAE;gBAC5B,CAAC,CAAC,GAAG,cAAc,IAAI,IAAI,EAAE;YAC/B,CAAC,CAAC,IAAI,CAAA;IACV,CAAC,CAAA;IAED,MAAM,mBAAmB,GAAG,GAAG,EAAE;QAC/B,IAAI,CAAC,cAAc;YAAE,OAAM;QAC3B,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QACjC,cAAc,GAAG,IAAI,CAAA;IACvB,CAAC,CAAA;IAED,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAE,CAAA;QAEhC,IAAI,IAAI,KAAK,GAAG,IAAI,cAAc,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAClD,cAAc,IAAI,IAAI,CAAA;YACtB,wBAAwB,EAAE,CAAA;YAC1B,SAAQ;QACV,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,IAAI,wBAAwB,GAAG,CAAC,EAAE,CAAC;YACjD,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;YACnE,wBAAwB,EAAE,CAAA;YAC1B,SAAQ;QACV,CAAC;QAED,IAAK,qBAAqC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACrD,mBAAmB,EAAE,CAAA;YACrB,SAAQ;QACV,CAAC;QAED,IAAK,wBAAwC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACxD,mBAAmB,EAAE,CAAA;YACrB,SAAQ;QACV,CAAC;QAED,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,cAAc,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;YACvC,IACE,QAAQ;gBACR,CAAE,wBAAwC,CAAC,GAAG,CAAC,QAAQ,CAAC;gBACxD,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAChC,CAAC;gBACD,cAAc,GAAG,iBAAiB,CAAC,cAAc,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;gBAClE,KAAK,EAAE,CAAA;YACT,CAAC;iBAAM,CAAC;gBACN,cAAc,GAAG,iBAAiB,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;YAC1D,CAAC;YACD,SAAQ;QACV,CAAC;QAED,UAAU,CAAC,IAAI,CAAC,CAAA;IAClB,CAAC;IAED,mBAAmB,EAAE,CAAA;IACrB,OAAO,YAAY,CAAA;AACrB,CAAC;AAEM,KAAK,UAAU,gBAAgB,CACpC,OAAe,EACf,WAAwB,EACxB,SAAkB;IAElB,IAAI,QAAQ,CAAA;IACZ,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,IAAA,qBAAU,EAAC;YAC1B,YAAY,EAAE;gBACZ;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,uCAA4B;iBACnC;aACF;YACD,UAAU,EAAE,IAAA,qCAA0B,EAAC,OAAO,CAAC;YAC/C,MAAM,EAAE,WAAW;YACnB,cAAc,EAAE,KAAK;YACrB,SAAS;SACV,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,MAAM,GAAG,CACb,OAAO,QAAQ,CAAC,OAAO,CAAC,OAAO,KAAK,QAAQ;QAC1C,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO;QAC1B,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC;YACvC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI;gBAC5D,MAAM,CAAC;YACT,CAAC,CAAC,MAAM,CACb,CAAC,IAAI,EAAE,CAAA;IAER,IAAI,MAAM,CAAC,UAAU,CAAC,wBAAc,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,MAAM,KAAK,4BAA4B,EAAE,CAAC;QAC5C,OAAO,EAAE,wBAAwB,EAAE,IAAI,EAAE,CAAA;IAC3C,CAAC;IAED,0CAA0C;IAC1C,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,OAAO;YACL,aAAa,EAAE,IAAI;YACnB,wBAAwB,EAAE,KAAK;SAChC,CAAA;IACH,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO;YACL,aAAa,EAAE,IAAI;YACnB,wBAAwB,EAAE,KAAK;SAChC,CAAA;IACH,CAAC;IAED,OAAO;QACL,aAAa,EAAE,MAAM;QACrB,wBAAwB,EAAE,KAAK;KAChC,CAAA;AACH,CAAC;AAED,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAkB;IACrD,IAAI;IACJ,IAAI;IACJ,GAAG;IACH,IAAI;IACJ,GAAG;IACH,GAAG;IACH,IAAI;CACL,CAAC,CAAA;AAEF,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAS;IAC/C,GAAG,qBAAqB;IACxB,GAAG;IACH,GAAG;CACJ,CAAC,CAAA;AAEF,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAS;IAC/C,GAAG;IACH,GAAG;CACJ,CAAC,CAAA;AAEF,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAS;IAClD,GAAG;IACH,GAAG;IACH,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,KAAK;CACN,CAAC,CAAA;AAEF,SAAS,qBAAqB,CAAC,IAAY;IACzC,OAAO,2BAA2B,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpF,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe,EAAE,QAAgB,EAAE,MAAe;IAC3E,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,OAAO,CAAA;IAC9C,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAA;IACnE,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,WAAW,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,WAAW,EAAE,CAAA;AACnF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.test.d.ts","sourceRoot":"","sources":["../../src/util/commands.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const commands_1 = require("./commands");
|
|
9
|
+
(0, node_test_1.test)('引号外元字符判为注入', () => {
|
|
10
|
+
for (const c of [
|
|
11
|
+
'echo a; rm x',
|
|
12
|
+
'ls && rm',
|
|
13
|
+
'ls || rm',
|
|
14
|
+
'echo $(id)',
|
|
15
|
+
'echo `id`',
|
|
16
|
+
'cat a\nrm b',
|
|
17
|
+
]) {
|
|
18
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)(c), true, c);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
(0, node_test_1.test)('回归: 引号内的换行/分号是字面数据,不得判为注入', () => {
|
|
22
|
+
// 多行 echo —— 此前因双引号内换行被误判为注入,导致 AutoRun 不调模型直接转人工
|
|
23
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "banana\napple\n100"'), false);
|
|
24
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "a;b"'), false);
|
|
25
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)("echo 'a;b;c'"), false);
|
|
26
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)("echo '$(id)'"), false);
|
|
27
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "he said \\"hi\\""'), false);
|
|
28
|
+
});
|
|
29
|
+
(0, node_test_1.test)('双引号内命令替换仍生效,必须判为注入', () => {
|
|
30
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "$(id)"'), true);
|
|
31
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "`id`"'), true);
|
|
32
|
+
});
|
|
33
|
+
// ============ 误伤回归:以下都是合法命令,绝不能判为注入 ============
|
|
34
|
+
(0, node_test_1.test)('误伤回归: 引号内含 shell 元字符的合法命令', () => {
|
|
35
|
+
for (const c of [
|
|
36
|
+
'echo "hello world"',
|
|
37
|
+
'git commit -m "fix: handle a, b and c"',
|
|
38
|
+
'python -c "print(\'hello\')"', // 双引号内嵌单引号
|
|
39
|
+
'node -e "console.log(1+1)"',
|
|
40
|
+
'grep -E "foo|bar" file', // 双引号内管道是字面
|
|
41
|
+
"grep -E 'foo|bar' .", // 单引号内管道是字面
|
|
42
|
+
"awk '{print $1}' data.txt", // 单引号内 $1
|
|
43
|
+
"sed 's/a/b/g' file",
|
|
44
|
+
'echo "price is $5 today"', // $ 后非 ( 不算替换
|
|
45
|
+
'echo "say \\"hi\\" now"', // 双引号内转义引号
|
|
46
|
+
'echo "a && b || c ; d"', // 全在双引号内 → 字面
|
|
47
|
+
"echo 'a && b || c ; d'", // 单引号内 → 字面
|
|
48
|
+
'psql -c "SELECT 1; SELECT 2;"', // 双引号内分号是合法 SQL
|
|
49
|
+
'echo "var=${HOME}/bin"', // ${} 不是命令替换
|
|
50
|
+
'echo "literal backslash-n: a\\nb"', // 字面 \n(非真换行)
|
|
51
|
+
'find . -name "*.ts"',
|
|
52
|
+
'git log --pretty=format:"%h %s"',
|
|
53
|
+
'echo "url=http://a.com?x=1&y=2"', // 单个 & 在双引号内
|
|
54
|
+
]) {
|
|
55
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)(c), false, `不应误伤: ${JSON.stringify(c)}`);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
(0, node_test_1.test)('误伤回归: 多行文本(你的原始场景)', () => {
|
|
59
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "banana\napple\ncherry\n100"'), false);
|
|
60
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)("printf '%s\\n' 'line1\nline2'"), false);
|
|
61
|
+
});
|
|
62
|
+
// ============ 真注入:必须检出 ============
|
|
63
|
+
(0, node_test_1.test)('真注入: 引号外的命令分隔/替换必须检出', () => {
|
|
64
|
+
for (const c of [
|
|
65
|
+
'ls; rm -rf /',
|
|
66
|
+
'ls && rm x',
|
|
67
|
+
'ls || rm x',
|
|
68
|
+
'echo $(whoami)',
|
|
69
|
+
'echo `whoami`',
|
|
70
|
+
'cat a\nrm b', // 引号外真实换行
|
|
71
|
+
'echo "$(cat /etc/passwd)"', // 双引号内命令替换
|
|
72
|
+
'foo "abc"; rm bar', // 引号闭合后的分号
|
|
73
|
+
"cat 'x'`id`", // 单引号闭合后反引号
|
|
74
|
+
]) {
|
|
75
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)(c), true, `应检出注入: ${JSON.stringify(c)}`);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
// ============ 边界行为文档化(断言实际行为,便于回归对比)============
|
|
79
|
+
(0, node_test_1.test)('边界: 反斜杠转义的字符不参与判定', () => {
|
|
80
|
+
// 双引号内转义的 $ / 反引号是字面,不是命令替换
|
|
81
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "\\$(not sub)"'), false);
|
|
82
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "\\`not sub\\`"'), false);
|
|
83
|
+
// 行连接符 \<换行> 是续行,被转义跳过,不算注入
|
|
84
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo a \\\nb'), false);
|
|
85
|
+
});
|
|
86
|
+
(0, node_test_1.test)('边界: $(( 算术展开仍按注入处理(与历史行为一致,偏保守)', () => {
|
|
87
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo $((1+1))'), true);
|
|
88
|
+
});
|
|
89
|
+
(0, node_test_1.test)('边界: 未闭合引号内的分隔符不检出(命令本身在 shell 中即语法错误)', () => {
|
|
90
|
+
// 双引号未闭合 → 整段被当引号内,; 不检出;该命令在 shell 中会因 EOF 报错而不执行
|
|
91
|
+
strict_1.default.equal((0, commands_1.hasCommandInjection)('echo "a; rm b'), false);
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=commands.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.test.js","sourceRoot":"","sources":["../../src/util/commands.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fetch_url 的确定性 SSRF 兜底:命中环回 / 链路本地(含云元数据 169.254.169.254)/
|
|
3
|
+
* 内网 / 未指定地址 / 本地主机名,一律按危险处理,不交给模型。URL 解析失败同样按危险处理。
|
|
4
|
+
*
|
|
5
|
+
* 说明:new URL() (WHATWG) 已把 十进制/十六进制/八进制/短写 IPv4(如 2130706433、0x7f000001、
|
|
6
|
+
* 127.1)规范化为点分十进制,故无需额外处理;这里额外补:
|
|
7
|
+
* - IPv4-mapped IPv6(::ffff:7f00:1 等)
|
|
8
|
+
* - 末尾点 FQDN(localhost. 等)
|
|
9
|
+
*/
|
|
10
|
+
export declare function isBlockedFetchHost(url: string): boolean;
|
|
11
|
+
//# sourceMappingURL=fetchSafety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchSafety.d.ts","sourceRoot":"","sources":["../../src/util/fetchSafety.ts"],"names":[],"mappings":"AAoBA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA2CvD"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isBlockedFetchHost = isBlockedFetchHost;
|
|
4
|
+
/**
|
|
5
|
+
* IPv4-mapped IPv6 → 内嵌 IPv4 点分形式。
|
|
6
|
+
* Node 的 URL 会把 ::ffff:127.0.0.1 规范化为 ::ffff:7f00:1,两种写法都要还原。
|
|
7
|
+
* ::ffff:127.0.0.1 → "127.0.0.1"
|
|
8
|
+
* ::ffff:7f00:1 → "127.0.0.1"
|
|
9
|
+
*/
|
|
10
|
+
function extractMappedIpv4(host) {
|
|
11
|
+
const m = host.match(/^::ffff:(.+)$/i);
|
|
12
|
+
if (!m)
|
|
13
|
+
return null;
|
|
14
|
+
const tail = m[1];
|
|
15
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(tail))
|
|
16
|
+
return tail;
|
|
17
|
+
const hex = tail.match(/^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);
|
|
18
|
+
if (hex) {
|
|
19
|
+
const hi = parseInt(hex[1], 16);
|
|
20
|
+
const lo = parseInt(hex[2], 16);
|
|
21
|
+
return `${(hi >> 8) & 255}.${hi & 255}.${(lo >> 8) & 255}.${lo & 255}`;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* fetch_url 的确定性 SSRF 兜底:命中环回 / 链路本地(含云元数据 169.254.169.254)/
|
|
27
|
+
* 内网 / 未指定地址 / 本地主机名,一律按危险处理,不交给模型。URL 解析失败同样按危险处理。
|
|
28
|
+
*
|
|
29
|
+
* 说明:new URL() (WHATWG) 已把 十进制/十六进制/八进制/短写 IPv4(如 2130706433、0x7f000001、
|
|
30
|
+
* 127.1)规范化为点分十进制,故无需额外处理;这里额外补:
|
|
31
|
+
* - IPv4-mapped IPv6(::ffff:7f00:1 等)
|
|
32
|
+
* - 末尾点 FQDN(localhost. 等)
|
|
33
|
+
*/
|
|
34
|
+
function isBlockedFetchHost(url) {
|
|
35
|
+
let hostname;
|
|
36
|
+
try {
|
|
37
|
+
hostname = new URL(url).hostname.toLowerCase();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
// 去掉 IPv6 字面量方括号,并去掉末尾点(FQDN 绝对形式,如 localhost.)
|
|
43
|
+
let host = hostname.replace(/^\[|\]$/g, '').replace(/\.$/, '');
|
|
44
|
+
// 本地主机名 / 已知云元数据主机名
|
|
45
|
+
if (host === 'localhost' || host.endsWith('.localhost'))
|
|
46
|
+
return true;
|
|
47
|
+
if (host === 'metadata.google.internal')
|
|
48
|
+
return true;
|
|
49
|
+
// IPv4-mapped IPv6 → 取出内嵌 IPv4,按下方 IPv4 规则判定
|
|
50
|
+
const mapped = extractMappedIpv4(host);
|
|
51
|
+
if (mapped)
|
|
52
|
+
host = mapped;
|
|
53
|
+
// IPv4 字面量
|
|
54
|
+
const ipv4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
55
|
+
if (ipv4) {
|
|
56
|
+
const a = Number(ipv4[1]);
|
|
57
|
+
const b = Number(ipv4[2]);
|
|
58
|
+
if (a === 0)
|
|
59
|
+
return true; // 0.0.0.0/8 未指定
|
|
60
|
+
if (a === 10)
|
|
61
|
+
return true; // 10.0.0.0/8 私网
|
|
62
|
+
if (a === 127)
|
|
63
|
+
return true; // 127.0.0.0/8 环回
|
|
64
|
+
if (a === 169 && b === 254)
|
|
65
|
+
return true; // 169.254.0.0/16 链路本地(含元数据)
|
|
66
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
67
|
+
return true; // 172.16.0.0/12 私网
|
|
68
|
+
if (a === 192 && b === 168)
|
|
69
|
+
return true; // 192.168.0.0/16 私网
|
|
70
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
71
|
+
return true; // 100.64.0.0/10 CGNAT
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
// IPv6 字面量:环回 / 未指定 / ULA(fc00::/7) / 链路本地(fe80::/10)
|
|
75
|
+
if (host.includes(':')) {
|
|
76
|
+
if (host === '::1' || host === '::')
|
|
77
|
+
return true;
|
|
78
|
+
if (/^f[cd]/.test(host))
|
|
79
|
+
return true; // fc00::/7
|
|
80
|
+
if (/^fe[89ab]/.test(host))
|
|
81
|
+
return true; // fe80::/10
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=fetchSafety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchSafety.js","sourceRoot":"","sources":["../../src/util/fetchSafety.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchSafety.test.d.ts","sourceRoot":"","sources":["../../src/util/fetchSafety.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const fetchSafety_1 = require("./fetchSafety");
|
|
9
|
+
(0, node_test_1.test)('环回/内网/链路本地/元数据 拦截', () => {
|
|
10
|
+
for (const u of [
|
|
11
|
+
'http://127.0.0.1/', 'http://localhost/', 'http://10.0.0.5/',
|
|
12
|
+
'http://192.168.1.1/', 'http://172.16.0.1/',
|
|
13
|
+
'http://169.254.169.254/latest/meta-data/',
|
|
14
|
+
'http://metadata.google.internal/', 'http://[::1]/',
|
|
15
|
+
'http://100.64.0.1/',
|
|
16
|
+
]) {
|
|
17
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)(u), true, u);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
(0, node_test_1.test)('回归: IPv4 数值/短写编码 (URL 规范化后) 仍拦截', () => {
|
|
21
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)('http://2130706433/'), true); // 127.0.0.1
|
|
22
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)('http://0x7f000001/'), true);
|
|
23
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)('http://127.1/'), true);
|
|
24
|
+
});
|
|
25
|
+
(0, node_test_1.test)('回归: IPv4-mapped IPv6 拦截', () => {
|
|
26
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)('http://[::ffff:127.0.0.1]/'), true);
|
|
27
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)('http://[::ffff:7f00:1]/'), true); // 127.0.0.1
|
|
28
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)('http://[::ffff:169.254.169.254]/'), true);
|
|
29
|
+
});
|
|
30
|
+
(0, node_test_1.test)('回归: 末尾点 FQDN 拦截', () => {
|
|
31
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)('http://localhost./'), true);
|
|
32
|
+
});
|
|
33
|
+
(0, node_test_1.test)('公网正常域名放行', () => {
|
|
34
|
+
for (const u of [
|
|
35
|
+
'https://registry.npmjs.org/react',
|
|
36
|
+
'https://github.com/x/y', 'https://8.8.8.8/',
|
|
37
|
+
]) {
|
|
38
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)(u), false, u);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
(0, node_test_1.test)('非法 URL 按危险处理', () => {
|
|
42
|
+
strict_1.default.equal((0, fetchSafety_1.isBlockedFetchHost)('not a url'), true);
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=fetchSafety.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchSafety.test.js","sourceRoot":"","sources":["../../src/util/fetchSafety.test.ts"],"names":[],"mappings":";;;;;AAAA,yCAAgC;AAChC,gEAAuC;AACvC,+CAAkD;AAElD,IAAA,gBAAI,EAAC,mBAAmB,EAAE,GAAG,EAAE;IAC7B,KAAK,MAAM,CAAC,IAAI;QACd,mBAAmB,EAAE,mBAAmB,EAAE,kBAAkB;QAC5D,qBAAqB,EAAE,oBAAoB;QAC3C,0CAA0C;QAC1C,kCAAkC,EAAE,eAAe;QACnD,oBAAoB;KACrB,EAAE,CAAC;QACF,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC9C,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,IAAA,gBAAI,EAAC,iCAAiC,EAAE,GAAG,EAAE;IAC3C,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC,CAAA,CAAG,YAAY;IAC3E,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC,CAAA;IAC5D,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,eAAe,CAAC,EAAE,IAAI,CAAC,CAAA;AACzD,CAAC,CAAC,CAAA;AAEF,IAAA,gBAAI,EAAC,yBAAyB,EAAE,GAAG,EAAE;IACnC,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,4BAA4B,CAAC,EAAE,IAAI,CAAC,CAAA;IACpE,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,yBAAyB,CAAC,EAAE,IAAI,CAAC,CAAA,CAAO,YAAY;IACpF,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,kCAAkC,CAAC,EAAE,IAAI,CAAC,CAAA;AAC5E,CAAC,CAAC,CAAA;AAEF,IAAA,gBAAI,EAAC,iBAAiB,EAAE,GAAG,EAAE;IAC3B,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC,CAAA;AAC9D,CAAC,CAAC,CAAA;AAEF,IAAA,gBAAI,EAAC,UAAU,EAAE,GAAG,EAAE;IACpB,KAAK,MAAM,CAAC,IAAI;QACd,kCAAkC;QAClC,wBAAwB,EAAE,kBAAkB;KAC7C,EAAE,CAAC;QACF,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAC/C,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,IAAA,gBAAI,EAAC,cAAc,EAAE,GAAG,EAAE;IACxB,gBAAM,CAAC,KAAK,CAAC,IAAA,gCAAkB,EAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAA;AACrD,CAAC,CAAC,CAAA"}
|
package/dist/util/fetchUrl.d.ts
CHANGED
|
@@ -13,6 +13,6 @@ type RedirectRecord = {
|
|
|
13
13
|
statusCode: number;
|
|
14
14
|
};
|
|
15
15
|
export declare function fetchUrlAsMarkdown(url: string, abortController: AbortController): Promise<FetchUrlResult | RedirectRecord>;
|
|
16
|
-
export declare function injectPromptIntoMarkdown(prompt: string, markdownContent: string, signal: AbortSignal): Promise<string>;
|
|
16
|
+
export declare function injectPromptIntoMarkdown(prompt: string, markdownContent: string, signal: AbortSignal, sessionId?: string): Promise<string>;
|
|
17
17
|
export {};
|
|
18
18
|
//# sourceMappingURL=fetchUrl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchUrl.d.ts","sourceRoot":"","sources":["../../src/util/fetchUrl.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,0BAA0B,QAAS,CAAA;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAQD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,cAAc,GAAG,cAAc,CAAC,CAsE1C;AAED,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"fetchUrl.d.ts","sourceRoot":"","sources":["../../src/util/fetchUrl.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,0BAA0B,QAAS,CAAA;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAQD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,cAAc,GAAG,cAAc,CAAC,CAsE1C;AAED,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,WAAW,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAiBjB"}
|
package/dist/util/fetchUrl.js
CHANGED
|
@@ -81,13 +81,13 @@ async function fetchUrlAsMarkdown(url, abortController) {
|
|
|
81
81
|
contentType,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
-
async function injectPromptIntoMarkdown(prompt, markdownContent, signal) {
|
|
84
|
+
async function injectPromptIntoMarkdown(prompt, markdownContent, signal, sessionId) {
|
|
85
85
|
const truncated = markdownContent.length > exports.FETCH_URL_MAX_MARKDOWN_LEN
|
|
86
86
|
? markdownContent.slice(0, exports.FETCH_URL_MAX_MARKDOWN_LEN) + '\n\n[Content trimmed — exceeded length limit.]'
|
|
87
87
|
: markdownContent;
|
|
88
88
|
const userPrompt = (0, fetchUrl_1.buildSecondaryModelPrompt)(truncated, prompt);
|
|
89
89
|
try {
|
|
90
|
-
const { message } = await (0, queryLLM_1.queryQuick)({ userPrompt, signal });
|
|
90
|
+
const { message } = await (0, queryLLM_1.queryQuick)({ userPrompt, signal, sessionId });
|
|
91
91
|
const firstBlock = message.content[0];
|
|
92
92
|
return firstBlock && 'text' in firstBlock ? firstBlock.text : 'The model returned an empty response.';
|
|
93
93
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchUrl.js","sourceRoot":"","sources":["../../src/util/fetchUrl.ts"],"names":[],"mappings":";;;AA8BA,gDAyEC;AAED,
|
|
1
|
+
{"version":3,"file":"fetchUrl.js","sourceRoot":"","sources":["../../src/util/fetchUrl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令是否含重定向。用于「前缀授权」纵深防御:前缀匹配只看首词,
|
|
3
|
+
* 而 `echo x > file` 的危险来自重定向,故含重定向的命令不应被前缀授权覆盖,
|
|
4
|
+
* 也不应向用户提供「按前缀授权」选项。
|
|
5
|
+
*
|
|
6
|
+
* 先用 splitCommand 规范化(它会把 `x>file` 这类无空格重定向还原成带空格的 ` > ` 形式,
|
|
7
|
+
* 并正确处理引号),再用 REDIRECTION_RE 检测;解析失败时保守按「含重定向」处理。
|
|
8
|
+
*/
|
|
9
|
+
export declare function hasRedirection(command: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* 命令是否含「语义危险」子命令:危险首词(rm/sudo/mv 等)或 find 危险 flag。
|
|
12
|
+
* 不含重定向——重定向是否危险取决于路径(项目内可能安全),应交给上层模型判断。
|
|
13
|
+
*
|
|
14
|
+
* 用于 AutoRun:命中即「确定性危险」,直接转人工,不调模型(避免模型误判 safe 放行)。
|
|
15
|
+
* 解析失败保守按「危险」处理(fail-closed)。
|
|
16
|
+
*/
|
|
17
|
+
export declare function hasDangerousCommand(command: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* 命令是否「不适合按前缀授权」。命中则:
|
|
20
|
+
* - checkRunShellPermission 不向用户提供「按前缀授权」选项(只许单次确认)
|
|
21
|
+
* - matchesSavedPrefix 即便命中已存前缀也不放行(纵深防御,治存量配置)
|
|
22
|
+
*
|
|
23
|
+
* 涵盖:含重定向 / 危险首词(rm、sudo、mv 等)/ find 危险 flag。
|
|
24
|
+
*/
|
|
25
|
+
export declare function isUnsafeForPrefixAuth(command: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* 整条命令是否可判定为「只读安全」,可直接放行(无需人工/模型)。
|
|
28
|
+
* 基于 splitCommand 的分词逐子命令判定,从根本上消除「整串 split(' ')[0]」带来的
|
|
29
|
+
* 重定向 / 不带空格管道 / find 等绕过:
|
|
30
|
+
* - 含 && || ; ` $( 换行 → 交上层逐子命令或人工,这里不放行
|
|
31
|
+
* - 含管道时,要求每一段首词都在只读集合且段内无重定向
|
|
32
|
+
*/
|
|
33
|
+
export declare function isReadonlySafeCommand(command: string): boolean;
|
|
34
|
+
//# sourceMappingURL=shellSafety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shellSafety.d.ts","sourceRoot":"","sources":["../../src/util/shellSafety.ts"],"names":[],"mappings":"AAsBA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOvD;AAqBD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ5D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE9D;AAWD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAW9D"}
|