@node9/proxy 2.16.1 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +270 -234
- package/dist/cli.mjs +270 -234
- package/dist/dashboard.mjs +2 -2
- package/dist/index.js +269 -233
- package/dist/index.mjs +269 -233
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -2100,30 +2100,213 @@ function analyzeShellCommand(command) {
|
|
|
2100
2100
|
}
|
|
2101
2101
|
return { actions, paths, allTokens };
|
|
2102
2102
|
}
|
|
2103
|
+
function parseComponent(s) {
|
|
2104
|
+
if (!s) return null;
|
|
2105
|
+
if (/^0[xX][0-9a-fA-F]+$/.test(s)) return parseInt(s.slice(2), 16);
|
|
2106
|
+
if (s === "0") return 0;
|
|
2107
|
+
if (/^0[0-7]+$/.test(s)) return parseInt(s.slice(1), 8);
|
|
2108
|
+
if (/^[1-9][0-9]*$/.test(s)) return Number(s);
|
|
2109
|
+
return null;
|
|
2110
|
+
}
|
|
2111
|
+
function parseIpv4(input) {
|
|
2112
|
+
let s = input;
|
|
2113
|
+
if (s.endsWith(".")) s = s.slice(0, -1);
|
|
2114
|
+
if (!s) return null;
|
|
2115
|
+
const parts = s.split(".");
|
|
2116
|
+
if (parts.length > 4) return null;
|
|
2117
|
+
const vals = [];
|
|
2118
|
+
for (const p of parts) {
|
|
2119
|
+
const v = parseComponent(p);
|
|
2120
|
+
if (v === null || !Number.isFinite(v) || v < 0) return null;
|
|
2121
|
+
vals.push(v);
|
|
2122
|
+
}
|
|
2123
|
+
const n = vals.length;
|
|
2124
|
+
for (let i = 0; i < n - 1; i++) if (vals[i] > 255) return null;
|
|
2125
|
+
const last = vals[n - 1];
|
|
2126
|
+
const remainingBytes = 4 - (n - 1);
|
|
2127
|
+
const limit = Math.pow(256, remainingBytes);
|
|
2128
|
+
if (last >= limit) return null;
|
|
2129
|
+
let value = last;
|
|
2130
|
+
for (let i = 0; i < n - 1; i++) value += vals[i] * Math.pow(256, 3 - i);
|
|
2131
|
+
if (value > 4294967295) return null;
|
|
2132
|
+
return [value >>> 24 & 255, value >>> 16 & 255, value >>> 8 & 255, value & 255].join(".");
|
|
2133
|
+
}
|
|
2134
|
+
function expandIpv6(input) {
|
|
2135
|
+
const s = input.toLowerCase();
|
|
2136
|
+
if (!/^[0-9a-f:.]+$/.test(s)) return null;
|
|
2137
|
+
if ((s.match(/::/g) ?? []).length > 1) return null;
|
|
2138
|
+
let head = s;
|
|
2139
|
+
let tailV4 = null;
|
|
2140
|
+
const lastColon = s.lastIndexOf(":");
|
|
2141
|
+
const afterLast = s.slice(lastColon + 1);
|
|
2142
|
+
if (afterLast.includes(".")) {
|
|
2143
|
+
const dotted = parseIpv4(afterLast);
|
|
2144
|
+
if (!dotted) return null;
|
|
2145
|
+
const o = dotted.split(".").map(Number);
|
|
2146
|
+
tailV4 = [o[0] << 8 | o[1], o[2] << 8 | o[3]];
|
|
2147
|
+
head = s.slice(0, lastColon + 1) + "0";
|
|
2148
|
+
}
|
|
2149
|
+
const [lhs, rhs] = head.includes("::") ? head.split("::") : [head, null];
|
|
2150
|
+
const toGroups = (part) => {
|
|
2151
|
+
if (!part) return [];
|
|
2152
|
+
const out = [];
|
|
2153
|
+
for (const g of part.split(":")) {
|
|
2154
|
+
if (!/^[0-9a-f]{1,4}$/.test(g)) return null;
|
|
2155
|
+
out.push(parseInt(g, 16));
|
|
2156
|
+
}
|
|
2157
|
+
return out;
|
|
2158
|
+
};
|
|
2159
|
+
const left = toGroups(lhs);
|
|
2160
|
+
if (left === null) return null;
|
|
2161
|
+
let right = [];
|
|
2162
|
+
if (rhs !== null) {
|
|
2163
|
+
const r = toGroups(rhs);
|
|
2164
|
+
if (r === null) return null;
|
|
2165
|
+
right = r;
|
|
2166
|
+
}
|
|
2167
|
+
if (tailV4) {
|
|
2168
|
+
if (rhs !== null) right = right.slice(0, -1).concat(tailV4);
|
|
2169
|
+
else left.splice(left.length - 1, 1, ...tailV4);
|
|
2170
|
+
}
|
|
2171
|
+
const groups = rhs === null ? left : left.concat(new Array(8 - left.length - right.length).fill(0), right);
|
|
2172
|
+
if (rhs === null && groups.length !== 8) return null;
|
|
2173
|
+
if (rhs !== null && left.length + right.length > 8) return null;
|
|
2174
|
+
if (groups.length !== 8) return null;
|
|
2175
|
+
return groups;
|
|
2176
|
+
}
|
|
2177
|
+
function compressIpv6(g) {
|
|
2178
|
+
let bestStart = -1;
|
|
2179
|
+
let bestLen = 0;
|
|
2180
|
+
let i = 0;
|
|
2181
|
+
while (i < 8) {
|
|
2182
|
+
if (g[i] !== 0) {
|
|
2183
|
+
i++;
|
|
2184
|
+
continue;
|
|
2185
|
+
}
|
|
2186
|
+
let j = i;
|
|
2187
|
+
while (j < 8 && g[j] === 0) j++;
|
|
2188
|
+
if (j - i > bestLen) {
|
|
2189
|
+
bestLen = j - i;
|
|
2190
|
+
bestStart = i;
|
|
2191
|
+
}
|
|
2192
|
+
i = j;
|
|
2193
|
+
}
|
|
2194
|
+
const hex = g.map((x) => x.toString(16));
|
|
2195
|
+
if (bestLen < 2) return hex.join(":");
|
|
2196
|
+
return hex.slice(0, bestStart).join(":") + "::" + hex.slice(bestStart + bestLen).join(":");
|
|
2197
|
+
}
|
|
2198
|
+
function normalizeIpLiteral(host) {
|
|
2199
|
+
try {
|
|
2200
|
+
if (typeof host !== "string") return null;
|
|
2201
|
+
let s = host.trim();
|
|
2202
|
+
if (!s || s.length > SSRF_MAX_HOST) return null;
|
|
2203
|
+
if (s.startsWith("[") && s.endsWith("]")) s = s.slice(1, -1);
|
|
2204
|
+
const zone = s.indexOf("%");
|
|
2205
|
+
if (zone >= 0) s = s.slice(0, zone);
|
|
2206
|
+
if (!s) return null;
|
|
2207
|
+
if (s.includes(":")) {
|
|
2208
|
+
const g = expandIpv6(s);
|
|
2209
|
+
if (!g) return null;
|
|
2210
|
+
const mapped = g.slice(0, 5).every((x) => x === 0) && g[5] === 65535;
|
|
2211
|
+
if (mapped) {
|
|
2212
|
+
return [g[6] >> 8 & 255, g[6] & 255, g[7] >> 8 & 255, g[7] & 255].join(".");
|
|
2213
|
+
}
|
|
2214
|
+
return compressIpv6(g);
|
|
2215
|
+
}
|
|
2216
|
+
return parseIpv4(s);
|
|
2217
|
+
} catch {
|
|
2218
|
+
return null;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
function isStrictGatedTier(tier) {
|
|
2222
|
+
return STRICT_TIERS.has(tier);
|
|
2223
|
+
}
|
|
2224
|
+
function ssrfReason(m, asWritten) {
|
|
2225
|
+
return `Blocked: ${asWritten} is ${TIER_REASON[m.tier]}` + (m.normalized && m.normalized !== asWritten ? ` (${m.normalized})` : "") + (m.overridable ? "." : ". This address cannot be allowlisted.");
|
|
2226
|
+
}
|
|
2227
|
+
function classifySsrf(host) {
|
|
2228
|
+
try {
|
|
2229
|
+
if (typeof host !== "string" || !host) return null;
|
|
2230
|
+
const lower = host.trim().toLowerCase().replace(/\.$/, "");
|
|
2231
|
+
const ip = normalizeIpLiteral(host);
|
|
2232
|
+
if (ip === null) {
|
|
2233
|
+
return METADATA_HOSTNAMES.has(lower) ? { tier: "metadata", overridable: false, kind: "hostname" } : null;
|
|
2234
|
+
}
|
|
2235
|
+
const hit = (tier, overridable) => ({
|
|
2236
|
+
tier,
|
|
2237
|
+
overridable,
|
|
2238
|
+
kind: "address",
|
|
2239
|
+
normalized: ip
|
|
2240
|
+
});
|
|
2241
|
+
if (METADATA_ADDRESSES.has(ip)) return hit("metadata", false);
|
|
2242
|
+
const o = v4Octets(ip);
|
|
2243
|
+
if (o) {
|
|
2244
|
+
if (o[0] === 0 && o[1] === 0 && o[2] === 0 && o[3] === 0) return hit("unspecified", true);
|
|
2245
|
+
if (o[0] === 169 && o[1] === 254) return hit("link-local", false);
|
|
2246
|
+
if (o[0] >= 224 && o[0] <= 239) return hit("multicast", false);
|
|
2247
|
+
if (o[0] === 100 && o[1] >= 64 && o[1] <= 127) return hit("cgnat", true);
|
|
2248
|
+
if (o[0] === 127) return hit("private", true);
|
|
2249
|
+
if (o[0] === 10) return hit("private", true);
|
|
2250
|
+
if (o[0] === 192 && o[1] === 168) return hit("private", true);
|
|
2251
|
+
if (o[0] === 172 && o[1] >= 16 && o[1] <= 31) return hit("private", true);
|
|
2252
|
+
return null;
|
|
2253
|
+
}
|
|
2254
|
+
const g = expandIpv6(ip);
|
|
2255
|
+
if (!g) return null;
|
|
2256
|
+
if (g.every((x) => x === 0)) return hit("unspecified", true);
|
|
2257
|
+
if ((g[0] & 65472) === 65152) return hit("link-local", false);
|
|
2258
|
+
if ((g[0] & 65280) === 65280) return hit("multicast", false);
|
|
2259
|
+
if (g.slice(0, 7).every((x) => x === 0) && g[7] === 1) return hit("private", true);
|
|
2260
|
+
return null;
|
|
2261
|
+
} catch {
|
|
2262
|
+
return null;
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
function ssrfFloor(tokens, opts = {}) {
|
|
2266
|
+
const exempt2 = new Set(
|
|
2267
|
+
(opts.ssrfAllow ?? []).map((e) => normalizeIpLiteral(e) ?? e.trim().toLowerCase())
|
|
2268
|
+
);
|
|
2269
|
+
for (const { token, binary } of tokens) {
|
|
2270
|
+
const m = classifySsrf(token);
|
|
2271
|
+
if (!m) continue;
|
|
2272
|
+
if (isStrictGatedTier(m.tier) && !opts.ssrfStrict) continue;
|
|
2273
|
+
if (m.overridable && m.normalized && exempt2.has(m.normalized)) continue;
|
|
2274
|
+
return { ...m, host: token, binary, reason: ssrfReason(m, token) };
|
|
2275
|
+
}
|
|
2276
|
+
return null;
|
|
2277
|
+
}
|
|
2103
2278
|
function hostMatches(host, pattern) {
|
|
2104
|
-
const
|
|
2105
|
-
const p = pattern.toLowerCase().trim();
|
|
2279
|
+
const p = pattern.trim().toLowerCase();
|
|
2106
2280
|
if (!p) return false;
|
|
2107
2281
|
if (p === "*") return true;
|
|
2282
|
+
const h = canonicalHost(host);
|
|
2108
2283
|
if (p.startsWith("*.")) {
|
|
2109
|
-
const suffix = p.slice(2);
|
|
2284
|
+
const suffix = canonicalHost(p.slice(2));
|
|
2110
2285
|
return h === suffix || h.endsWith("." + suffix);
|
|
2111
2286
|
}
|
|
2112
|
-
return h === p;
|
|
2287
|
+
return h === canonicalHost(p);
|
|
2113
2288
|
}
|
|
2114
2289
|
function matchesAny(host, patterns) {
|
|
2115
|
-
for (const p of patterns) if (hostMatches(host, p)) return true;
|
|
2290
|
+
for (const p of patterns ?? []) if (hostMatches(host, p)) return true;
|
|
2116
2291
|
return false;
|
|
2117
2292
|
}
|
|
2293
|
+
function isUniqueLocalV6(host) {
|
|
2294
|
+
const ip = normalizeIpLiteral(host);
|
|
2295
|
+
if (!ip || !ip.includes(":")) return false;
|
|
2296
|
+
const g = expandIpv6(ip);
|
|
2297
|
+
return g !== null && (g[0] & 65024) === 64512;
|
|
2298
|
+
}
|
|
2118
2299
|
function isPrivateHost(host) {
|
|
2119
|
-
const h = host.toLowerCase();
|
|
2120
|
-
|
|
2121
|
-
if (
|
|
2122
|
-
if (
|
|
2123
|
-
if (
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2300
|
+
const h = host.trim().toLowerCase().replace(/\.$/, "");
|
|
2301
|
+
const m = classifySsrf(h);
|
|
2302
|
+
if (m) return m.kind === "address" && (m.tier === "private" || m.tier === "unspecified");
|
|
2303
|
+
if (h === "localhost") return true;
|
|
2304
|
+
if (PRIVATE_HOST_SUFFIXES.some((s) => h.endsWith(s))) return true;
|
|
2305
|
+
return isUniqueLocalV6(h);
|
|
2306
|
+
}
|
|
2307
|
+
function canonicalHost(host) {
|
|
2308
|
+
const ip = normalizeIpLiteral(host);
|
|
2309
|
+
return ip ?? host.trim().toLowerCase().replace(/\.$/, "");
|
|
2127
2310
|
}
|
|
2128
2311
|
function evaluateEgress(dests, policy) {
|
|
2129
2312
|
if (!policy.enabled) return null;
|
|
@@ -2343,181 +2526,6 @@ function extractAllSshHosts(tokens) {
|
|
|
2343
2526
|
}
|
|
2344
2527
|
return [...hosts].filter(Boolean);
|
|
2345
2528
|
}
|
|
2346
|
-
function parseComponent(s) {
|
|
2347
|
-
if (!s) return null;
|
|
2348
|
-
if (/^0[xX][0-9a-fA-F]+$/.test(s)) return parseInt(s.slice(2), 16);
|
|
2349
|
-
if (s === "0") return 0;
|
|
2350
|
-
if (/^0[0-7]+$/.test(s)) return parseInt(s.slice(1), 8);
|
|
2351
|
-
if (/^[1-9][0-9]*$/.test(s)) return Number(s);
|
|
2352
|
-
return null;
|
|
2353
|
-
}
|
|
2354
|
-
function parseIpv4(input) {
|
|
2355
|
-
let s = input;
|
|
2356
|
-
if (s.endsWith(".")) s = s.slice(0, -1);
|
|
2357
|
-
if (!s) return null;
|
|
2358
|
-
const parts = s.split(".");
|
|
2359
|
-
if (parts.length > 4) return null;
|
|
2360
|
-
const vals = [];
|
|
2361
|
-
for (const p of parts) {
|
|
2362
|
-
const v = parseComponent(p);
|
|
2363
|
-
if (v === null || !Number.isFinite(v) || v < 0) return null;
|
|
2364
|
-
vals.push(v);
|
|
2365
|
-
}
|
|
2366
|
-
const n = vals.length;
|
|
2367
|
-
for (let i = 0; i < n - 1; i++) if (vals[i] > 255) return null;
|
|
2368
|
-
const last = vals[n - 1];
|
|
2369
|
-
const remainingBytes = 4 - (n - 1);
|
|
2370
|
-
const limit = Math.pow(256, remainingBytes);
|
|
2371
|
-
if (last >= limit) return null;
|
|
2372
|
-
let value = last;
|
|
2373
|
-
for (let i = 0; i < n - 1; i++) value += vals[i] * Math.pow(256, 3 - i);
|
|
2374
|
-
if (value > 4294967295) return null;
|
|
2375
|
-
return [value >>> 24 & 255, value >>> 16 & 255, value >>> 8 & 255, value & 255].join(".");
|
|
2376
|
-
}
|
|
2377
|
-
function expandIpv6(input) {
|
|
2378
|
-
const s = input.toLowerCase();
|
|
2379
|
-
if (!/^[0-9a-f:.]+$/.test(s)) return null;
|
|
2380
|
-
if ((s.match(/::/g) ?? []).length > 1) return null;
|
|
2381
|
-
let head = s;
|
|
2382
|
-
let tailV4 = null;
|
|
2383
|
-
const lastColon = s.lastIndexOf(":");
|
|
2384
|
-
const afterLast = s.slice(lastColon + 1);
|
|
2385
|
-
if (afterLast.includes(".")) {
|
|
2386
|
-
const dotted = parseIpv4(afterLast);
|
|
2387
|
-
if (!dotted) return null;
|
|
2388
|
-
const o = dotted.split(".").map(Number);
|
|
2389
|
-
tailV4 = [o[0] << 8 | o[1], o[2] << 8 | o[3]];
|
|
2390
|
-
head = s.slice(0, lastColon + 1) + "0";
|
|
2391
|
-
}
|
|
2392
|
-
const [lhs, rhs] = head.includes("::") ? head.split("::") : [head, null];
|
|
2393
|
-
const toGroups = (part) => {
|
|
2394
|
-
if (!part) return [];
|
|
2395
|
-
const out = [];
|
|
2396
|
-
for (const g of part.split(":")) {
|
|
2397
|
-
if (!/^[0-9a-f]{1,4}$/.test(g)) return null;
|
|
2398
|
-
out.push(parseInt(g, 16));
|
|
2399
|
-
}
|
|
2400
|
-
return out;
|
|
2401
|
-
};
|
|
2402
|
-
const left = toGroups(lhs);
|
|
2403
|
-
if (left === null) return null;
|
|
2404
|
-
let right = [];
|
|
2405
|
-
if (rhs !== null) {
|
|
2406
|
-
const r = toGroups(rhs);
|
|
2407
|
-
if (r === null) return null;
|
|
2408
|
-
right = r;
|
|
2409
|
-
}
|
|
2410
|
-
if (tailV4) {
|
|
2411
|
-
if (rhs !== null) right = right.slice(0, -1).concat(tailV4);
|
|
2412
|
-
else left.splice(left.length - 1, 1, ...tailV4);
|
|
2413
|
-
}
|
|
2414
|
-
const groups = rhs === null ? left : left.concat(new Array(8 - left.length - right.length).fill(0), right);
|
|
2415
|
-
if (rhs === null && groups.length !== 8) return null;
|
|
2416
|
-
if (rhs !== null && left.length + right.length > 8) return null;
|
|
2417
|
-
if (groups.length !== 8) return null;
|
|
2418
|
-
return groups;
|
|
2419
|
-
}
|
|
2420
|
-
function compressIpv6(g) {
|
|
2421
|
-
let bestStart = -1;
|
|
2422
|
-
let bestLen = 0;
|
|
2423
|
-
let i = 0;
|
|
2424
|
-
while (i < 8) {
|
|
2425
|
-
if (g[i] !== 0) {
|
|
2426
|
-
i++;
|
|
2427
|
-
continue;
|
|
2428
|
-
}
|
|
2429
|
-
let j = i;
|
|
2430
|
-
while (j < 8 && g[j] === 0) j++;
|
|
2431
|
-
if (j - i > bestLen) {
|
|
2432
|
-
bestLen = j - i;
|
|
2433
|
-
bestStart = i;
|
|
2434
|
-
}
|
|
2435
|
-
i = j;
|
|
2436
|
-
}
|
|
2437
|
-
const hex = g.map((x) => x.toString(16));
|
|
2438
|
-
if (bestLen < 2) return hex.join(":");
|
|
2439
|
-
return hex.slice(0, bestStart).join(":") + "::" + hex.slice(bestStart + bestLen).join(":");
|
|
2440
|
-
}
|
|
2441
|
-
function normalizeIpLiteral(host) {
|
|
2442
|
-
try {
|
|
2443
|
-
if (typeof host !== "string") return null;
|
|
2444
|
-
let s = host.trim();
|
|
2445
|
-
if (!s || s.length > SSRF_MAX_HOST) return null;
|
|
2446
|
-
if (s.startsWith("[") && s.endsWith("]")) s = s.slice(1, -1);
|
|
2447
|
-
const zone = s.indexOf("%");
|
|
2448
|
-
if (zone >= 0) s = s.slice(0, zone);
|
|
2449
|
-
if (!s) return null;
|
|
2450
|
-
if (s.includes(":")) {
|
|
2451
|
-
const g = expandIpv6(s);
|
|
2452
|
-
if (!g) return null;
|
|
2453
|
-
const mapped = g.slice(0, 5).every((x) => x === 0) && g[5] === 65535;
|
|
2454
|
-
if (mapped) {
|
|
2455
|
-
return [g[6] >> 8 & 255, g[6] & 255, g[7] >> 8 & 255, g[7] & 255].join(".");
|
|
2456
|
-
}
|
|
2457
|
-
return compressIpv6(g);
|
|
2458
|
-
}
|
|
2459
|
-
return parseIpv4(s);
|
|
2460
|
-
} catch {
|
|
2461
|
-
return null;
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
|
-
function isStrictGatedTier(tier) {
|
|
2465
|
-
return STRICT_TIERS.has(tier);
|
|
2466
|
-
}
|
|
2467
|
-
function ssrfReason(m, asWritten) {
|
|
2468
|
-
return `Blocked: ${asWritten} is ${TIER_REASON[m.tier]}` + (m.normalized && m.normalized !== asWritten ? ` (${m.normalized})` : "") + (m.overridable ? "." : ". This address cannot be allowlisted.");
|
|
2469
|
-
}
|
|
2470
|
-
function classifySsrf(host) {
|
|
2471
|
-
try {
|
|
2472
|
-
if (typeof host !== "string" || !host) return null;
|
|
2473
|
-
const lower = host.trim().toLowerCase().replace(/\.$/, "");
|
|
2474
|
-
const ip = normalizeIpLiteral(host);
|
|
2475
|
-
if (ip === null) {
|
|
2476
|
-
return METADATA_HOSTNAMES.has(lower) ? { tier: "metadata", overridable: false, kind: "hostname" } : null;
|
|
2477
|
-
}
|
|
2478
|
-
const hit = (tier, overridable) => ({
|
|
2479
|
-
tier,
|
|
2480
|
-
overridable,
|
|
2481
|
-
kind: "address",
|
|
2482
|
-
normalized: ip
|
|
2483
|
-
});
|
|
2484
|
-
if (METADATA_ADDRESSES.has(ip)) return hit("metadata", false);
|
|
2485
|
-
const o = v4Octets(ip);
|
|
2486
|
-
if (o) {
|
|
2487
|
-
if (o[0] === 0 && o[1] === 0 && o[2] === 0 && o[3] === 0) return hit("unspecified", true);
|
|
2488
|
-
if (o[0] === 169 && o[1] === 254) return hit("link-local", false);
|
|
2489
|
-
if (o[0] >= 224 && o[0] <= 239) return hit("multicast", false);
|
|
2490
|
-
if (o[0] === 100 && o[1] >= 64 && o[1] <= 127) return hit("cgnat", true);
|
|
2491
|
-
if (o[0] === 127) return hit("private", true);
|
|
2492
|
-
if (o[0] === 10) return hit("private", true);
|
|
2493
|
-
if (o[0] === 192 && o[1] === 168) return hit("private", true);
|
|
2494
|
-
if (o[0] === 172 && o[1] >= 16 && o[1] <= 31) return hit("private", true);
|
|
2495
|
-
return null;
|
|
2496
|
-
}
|
|
2497
|
-
const g = expandIpv6(ip);
|
|
2498
|
-
if (!g) return null;
|
|
2499
|
-
if (g.every((x) => x === 0)) return hit("unspecified", true);
|
|
2500
|
-
if ((g[0] & 65472) === 65152) return hit("link-local", false);
|
|
2501
|
-
if ((g[0] & 65280) === 65280) return hit("multicast", false);
|
|
2502
|
-
if (g.slice(0, 7).every((x) => x === 0) && g[7] === 1) return hit("private", true);
|
|
2503
|
-
return null;
|
|
2504
|
-
} catch {
|
|
2505
|
-
return null;
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
function ssrfFloor(tokens, opts = {}) {
|
|
2509
|
-
const exempt2 = new Set(
|
|
2510
|
-
(opts.ssrfAllow ?? []).map((e) => normalizeIpLiteral(e) ?? e.trim().toLowerCase())
|
|
2511
|
-
);
|
|
2512
|
-
for (const { token, binary } of tokens) {
|
|
2513
|
-
const m = classifySsrf(token);
|
|
2514
|
-
if (!m) continue;
|
|
2515
|
-
if (isStrictGatedTier(m.tier) && !opts.ssrfStrict) continue;
|
|
2516
|
-
if (m.overridable && m.normalized && exempt2.has(m.normalized)) continue;
|
|
2517
|
-
return { ...m, host: token, binary, reason: ssrfReason(m, token) };
|
|
2518
|
-
}
|
|
2519
|
-
return null;
|
|
2520
|
-
}
|
|
2521
2529
|
function bareToolName(toolName) {
|
|
2522
2530
|
const parts = toolName.split("__");
|
|
2523
2531
|
return (parts.length >= 3 ? parts.slice(2).join("__") : toolName).toLowerCase();
|
|
@@ -2551,6 +2559,22 @@ function hostOf(value) {
|
|
|
2551
2559
|
return null;
|
|
2552
2560
|
}
|
|
2553
2561
|
}
|
|
2562
|
+
function extractToolDestinations(toolName, args) {
|
|
2563
|
+
try {
|
|
2564
|
+
const paths = DESTINATION_ARGS.get(bareToolName(toolName));
|
|
2565
|
+
if (!paths) return [];
|
|
2566
|
+
const out = [];
|
|
2567
|
+
for (const path78 of paths) {
|
|
2568
|
+
for (const value of valuesAt(args, path78)) {
|
|
2569
|
+
const host = hostOf(value);
|
|
2570
|
+
if (host) out.push({ host, binary: toolName, raw: value });
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
return out;
|
|
2574
|
+
} catch {
|
|
2575
|
+
return [];
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2554
2578
|
function ssrfDestinationFloor(toolName, args, opts = {}) {
|
|
2555
2579
|
try {
|
|
2556
2580
|
const paths = DESTINATION_ARGS.get(bareToolName(toolName));
|
|
@@ -2652,6 +2676,16 @@ function pipeChainVerdict(command, isTrustedHost2, highAction = "review") {
|
|
|
2652
2676
|
tier: 3
|
|
2653
2677
|
};
|
|
2654
2678
|
}
|
|
2679
|
+
function egressPolicyVerdict(eg) {
|
|
2680
|
+
return {
|
|
2681
|
+
decision: eg.verdict,
|
|
2682
|
+
blockedByLabel: eg.verdict === "block" ? "\u{1F310} Node9 Egress (Blocked)" : "\u{1F310} Node9 Egress (Review)",
|
|
2683
|
+
reason: eg.reason,
|
|
2684
|
+
ruleName: `egress:${eg.binary}:${eg.host}`,
|
|
2685
|
+
ruleDescription: eg.reason,
|
|
2686
|
+
tier: eg.verdict === "block" ? 3 : 4
|
|
2687
|
+
};
|
|
2688
|
+
}
|
|
2655
2689
|
async function evaluatePolicy(config, toolName, args, context = {}, hooks = {}) {
|
|
2656
2690
|
const { agent, cwd, activeEnvironment } = context;
|
|
2657
2691
|
const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2 } = hooks;
|
|
@@ -2686,7 +2720,14 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
2686
2720
|
};
|
|
2687
2721
|
}
|
|
2688
2722
|
}
|
|
2689
|
-
|
|
2723
|
+
const pendingToolEgress = config.policy.egress?.enabled ? (() => {
|
|
2724
|
+
const dests = extractToolDestinations(toolName, args);
|
|
2725
|
+
const eg = dests.length > 0 ? evaluateEgress(dests, config.policy.egress) : null;
|
|
2726
|
+
return eg ? egressPolicyVerdict(eg) : void 0;
|
|
2727
|
+
})() : void 0;
|
|
2728
|
+
if (wouldBeIgnored && !context.skipIgnoredFastPath) {
|
|
2729
|
+
return pendingToolEgress ?? { decision: "allow" };
|
|
2730
|
+
}
|
|
2690
2731
|
const shellShaped = isBashTool(toolName) || inspectsShellCommand(toolName, config.policy.toolInspection);
|
|
2691
2732
|
const shellShapedCommand = shellShaped ? isBashTool(toolName) && args && typeof args === "object" ? typeof args.command === "string" ? args.command : null : extractShellCommand(toolName, args, config.policy.toolInspection) : null;
|
|
2692
2733
|
const bashCommand = agent !== "Terminal" ? shellShapedCommand : null;
|
|
@@ -2775,6 +2816,7 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
2775
2816
|
}
|
|
2776
2817
|
let allTokens = [];
|
|
2777
2818
|
let pathTokens = [];
|
|
2819
|
+
if (pendingToolEgress) return pendingToolEgress;
|
|
2778
2820
|
const shellCommand = extractShellCommand(toolName, args, config.policy.toolInspection);
|
|
2779
2821
|
if (shellCommand) {
|
|
2780
2822
|
const analyzed = analyzeShellCommand(shellCommand);
|
|
@@ -2840,16 +2882,7 @@ async function evaluatePolicy(config, toolName, args, context = {}, hooks = {})
|
|
|
2840
2882
|
const dests = extractShellDestinations(shellCommand);
|
|
2841
2883
|
if (dests.length > 0) {
|
|
2842
2884
|
const eg = evaluateEgress(dests, config.policy.egress);
|
|
2843
|
-
if (eg)
|
|
2844
|
-
return {
|
|
2845
|
-
decision: eg.verdict,
|
|
2846
|
-
blockedByLabel: eg.verdict === "block" ? "\u{1F310} Node9 Egress (Blocked)" : "\u{1F310} Node9 Egress (Review)",
|
|
2847
|
-
reason: eg.reason,
|
|
2848
|
-
ruleName: `egress:${eg.binary}:${eg.host}`,
|
|
2849
|
-
ruleDescription: eg.reason,
|
|
2850
|
-
tier: eg.verdict === "block" ? 3 : 4
|
|
2851
|
-
};
|
|
2852
|
-
}
|
|
2885
|
+
if (eg) return egressPolicyVerdict(eg);
|
|
2853
2886
|
}
|
|
2854
2887
|
}
|
|
2855
2888
|
const firstToken = analyzed.actions[0] ?? "";
|
|
@@ -3723,7 +3756,7 @@ function* stringValues(obj, depth = 0) {
|
|
|
3723
3756
|
}
|
|
3724
3757
|
for (const v of Object.values(obj)) yield* stringValues(v, depth + 1);
|
|
3725
3758
|
}
|
|
3726
|
-
var IBAN_LENGTH, B58, B58_INDEX, XPRV_VERSIONS, MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, DLP_SCAN_LIMITS, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, INTERP_LEADING_TARGET, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN,
|
|
3759
|
+
var IBAN_LENGTH, B58, B58_INDEX, XPRV_VERSIONS, MAX, UNTRUSTED_TOOLS, SIGNALS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, DLP_SCAN_LIMITS, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, SQL_DB_CLIS, SQL_DDL_RE, CHMOD_OPEN_PERM_TOKENS, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, _redirStdinOps, _listOps, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, INTERP_LEADING_TARGET, NET_BINARIES, VALUE_FLAGS, FS_OP_CACHE_MAX, fsOpCache, stripDotSlash, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, SSRF_MAX_HOST, METADATA_ADDRESSES, STRICT_TIERS, METADATA_HOSTNAMES, v4Octets, TIER_REASON, DEFAULT_EGRESS_ALLOWLIST, PRIVATE_HOST_SUFFIXES, SOURCE_COMMANDS, SINK_COMMANDS, OBFUSCATORS, SENSITIVE_PATTERNS, FLAGS_WITH_VALUES, DESTINATION_ARGS, VERDICT_RANK, SQL_DML_KEYWORDS, TERMINAL_ESCAPE_RE, CONTROL_CHAR_RE, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LOOP_MAX_RECORDS, FINDING_TO_SIGNAL, SCAN_SIGNAL_WEIGHTS, LOOP_THRESHOLD_FOR_WASTE, MAX_BLAST_PATH, DESTRUCTIVE_OP_RE, SENSITIVE_PATH_RE, FILE_TOOLS, PII_EMAIL_RE, PII_SSN_RE, PII_PHONE_RE, PII_CC16_RE, PII_CC15_RE, PII_IBAN_RE, REALTIME_PII_PATTERNS, MAX_PII_SCAN_BYTES, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH2, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES, CANONICAL_EXTRACTOR_VERSION, DEDUPE_PREVIEW_LEN, ENGINE_VERSION;
|
|
3727
3760
|
var init_dist = __esm({
|
|
3728
3761
|
"packages/policy-engine/dist/index.mjs"() {
|
|
3729
3762
|
"use strict";
|
|
@@ -5161,6 +5194,36 @@ var init_dist = __esm({
|
|
|
5161
5194
|
positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
5162
5195
|
NONE = { kind: "none" };
|
|
5163
5196
|
UNKNOWN = { kind: "unknown" };
|
|
5197
|
+
SSRF_MAX_HOST = 253;
|
|
5198
|
+
METADATA_ADDRESSES = /* @__PURE__ */ new Set([
|
|
5199
|
+
"169.254.169.254",
|
|
5200
|
+
// AWS / Azure / DigitalOcean / OpenStack IMDS
|
|
5201
|
+
"169.254.170.2",
|
|
5202
|
+
// AWS ECS task role
|
|
5203
|
+
"168.63.129.16",
|
|
5204
|
+
// Azure WireServer
|
|
5205
|
+
"fd00:ec2::254",
|
|
5206
|
+
// AWS IMDS over IPv6 (inside fc00::/7, which is NOT a tier)
|
|
5207
|
+
// Alibaba Cloud IMDS. It sits INSIDE 100.64/10, so before this line it was
|
|
5208
|
+
// classified as cgnat and therefore exemptable: one ssrfAllow entry opened a
|
|
5209
|
+
// live credential endpoint. It has to be named here, above the range check,
|
|
5210
|
+
// and it is the reason relaxing cgnat is safe.
|
|
5211
|
+
"100.100.100.200"
|
|
5212
|
+
]);
|
|
5213
|
+
STRICT_TIERS = /* @__PURE__ */ new Set(["private", "unspecified", "cgnat"]);
|
|
5214
|
+
METADATA_HOSTNAMES = /* @__PURE__ */ new Set(["metadata.google.internal", "metadata.goog", "metadata"]);
|
|
5215
|
+
v4Octets = (a) => {
|
|
5216
|
+
const p = a.split(".");
|
|
5217
|
+
return p.length === 4 ? p.map(Number) : null;
|
|
5218
|
+
};
|
|
5219
|
+
TIER_REASON = {
|
|
5220
|
+
metadata: "a cloud instance-metadata endpoint, the classic credential-theft target",
|
|
5221
|
+
"link-local": "a link-local address",
|
|
5222
|
+
multicast: "a multicast address",
|
|
5223
|
+
unspecified: "the unspecified address, which reaches this host",
|
|
5224
|
+
cgnat: "a carrier-grade NAT address",
|
|
5225
|
+
private: "a loopback or private address"
|
|
5226
|
+
};
|
|
5164
5227
|
DEFAULT_EGRESS_ALLOWLIST = [
|
|
5165
5228
|
// node9's own control plane (api, app, dev-api, staging and the apex).
|
|
5166
5229
|
// Without it, turning egress on asks the user to approve node9 itself.
|
|
@@ -5184,6 +5247,7 @@ var init_dist = __esm({
|
|
|
5184
5247
|
"deb.debian.org",
|
|
5185
5248
|
"*.ubuntu.com"
|
|
5186
5249
|
];
|
|
5250
|
+
PRIVATE_HOST_SUFFIXES = [".local", ".internal", ".localhost"];
|
|
5187
5251
|
SOURCE_COMMANDS = /* @__PURE__ */ new Set([...FS_READ_TOOLS, "tee"]);
|
|
5188
5252
|
SINK_COMMANDS = /* @__PURE__ */ new Set([
|
|
5189
5253
|
"curl",
|
|
@@ -5307,36 +5371,6 @@ var init_dist = __esm({
|
|
|
5307
5371
|
socat: /* @__PURE__ */ new Set([])
|
|
5308
5372
|
// socat uses address syntax, not flags — no value-flags
|
|
5309
5373
|
};
|
|
5310
|
-
SSRF_MAX_HOST = 253;
|
|
5311
|
-
METADATA_ADDRESSES = /* @__PURE__ */ new Set([
|
|
5312
|
-
"169.254.169.254",
|
|
5313
|
-
// AWS / Azure / DigitalOcean / OpenStack IMDS
|
|
5314
|
-
"169.254.170.2",
|
|
5315
|
-
// AWS ECS task role
|
|
5316
|
-
"168.63.129.16",
|
|
5317
|
-
// Azure WireServer
|
|
5318
|
-
"fd00:ec2::254",
|
|
5319
|
-
// AWS IMDS over IPv6 (inside fc00::/7, which is NOT a tier)
|
|
5320
|
-
// Alibaba Cloud IMDS. It sits INSIDE 100.64/10, so before this line it was
|
|
5321
|
-
// classified as cgnat and therefore exemptable: one ssrfAllow entry opened a
|
|
5322
|
-
// live credential endpoint. It has to be named here, above the range check,
|
|
5323
|
-
// and it is the reason relaxing cgnat is safe.
|
|
5324
|
-
"100.100.100.200"
|
|
5325
|
-
]);
|
|
5326
|
-
STRICT_TIERS = /* @__PURE__ */ new Set(["private", "unspecified", "cgnat"]);
|
|
5327
|
-
METADATA_HOSTNAMES = /* @__PURE__ */ new Set(["metadata.google.internal", "metadata.goog", "metadata"]);
|
|
5328
|
-
v4Octets = (a) => {
|
|
5329
|
-
const p = a.split(".");
|
|
5330
|
-
return p.length === 4 ? p.map(Number) : null;
|
|
5331
|
-
};
|
|
5332
|
-
TIER_REASON = {
|
|
5333
|
-
metadata: "a cloud instance-metadata endpoint, the classic credential-theft target",
|
|
5334
|
-
"link-local": "a link-local address",
|
|
5335
|
-
multicast: "a multicast address",
|
|
5336
|
-
unspecified: "the unspecified address, which reaches this host",
|
|
5337
|
-
cgnat: "a carrier-grade NAT address",
|
|
5338
|
-
private: "a loopback or private address"
|
|
5339
|
-
};
|
|
5340
5374
|
DESTINATION_ARGS = /* @__PURE__ */ new Map([
|
|
5341
5375
|
["webfetch", ["url"]],
|
|
5342
5376
|
["fetch", ["url", "uri"]],
|
|
@@ -9941,8 +9975,10 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
9941
9975
|
};
|
|
9942
9976
|
}
|
|
9943
9977
|
}
|
|
9978
|
+
const declaredEgress = config.policy.egress?.enabled === true && extractToolDestinations(toolName, args).length > 0;
|
|
9979
|
+
const judge = !isIgnoredTool2(toolName) || declaredEgress;
|
|
9944
9980
|
if (isObserveMode) {
|
|
9945
|
-
if (
|
|
9981
|
+
if (judge) {
|
|
9946
9982
|
const policyResult = await evaluatePolicy2(toolName, args, meta?.agent, options?.cwd);
|
|
9947
9983
|
const wouldBlock = policyResult.decision === "block";
|
|
9948
9984
|
if (!isManual)
|
|
@@ -9967,7 +10003,7 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
9967
10003
|
return { approved: true, checkedBy: "audit" };
|
|
9968
10004
|
}
|
|
9969
10005
|
if (config.settings.mode === "audit") {
|
|
9970
|
-
if (
|
|
10006
|
+
if (judge) {
|
|
9971
10007
|
const policyResult = await evaluatePolicy2(toolName, args, meta?.agent, options?.cwd);
|
|
9972
10008
|
if (policyResult.decision === "review") {
|
|
9973
10009
|
appendLocalAudit(toolName, args, "allow", "audit-mode", meta, hashAuditArgs);
|
|
@@ -10006,9 +10042,9 @@ async function _authorizeHeadlessCore(toolName, args, metaArg, options) {
|
|
|
10006
10042
|
appPermReviewTool = bareTool;
|
|
10007
10043
|
}
|
|
10008
10044
|
}
|
|
10009
|
-
if (!taintWarning &&
|
|
10045
|
+
if (!taintWarning && judge) {
|
|
10010
10046
|
const ld = config.policy.loopDetection;
|
|
10011
|
-
if (ld.enabled && !appPermReview) {
|
|
10047
|
+
if (ld.enabled && !appPermReview && !isIgnoredTool2(toolName)) {
|
|
10012
10048
|
const loopResult = recordAndCheck(toolName, args, ld.threshold, ld.windowSeconds * 1e3);
|
|
10013
10049
|
if (loopResult.looping) {
|
|
10014
10050
|
const reason = `It looks like you've called "${toolName}" ${loopResult.count} times with identical arguments in the last ${ld.windowSeconds}s. Are you stuck? Step back and reconsider your approach \u2014 what are you actually trying to accomplish, and is there a different way to get there?`;
|
package/dist/dashboard.mjs
CHANGED
|
@@ -1944,7 +1944,7 @@ function matchCanaryArgs(args, values) {
|
|
|
1944
1944
|
return null;
|
|
1945
1945
|
}
|
|
1946
1946
|
}
|
|
1947
|
-
var B58, B58_INDEX, XPRV_VERSIONS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_OP_CACHE_MAX, fsOpCache, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN,
|
|
1947
|
+
var B58, B58_INDEX, XPRV_VERSIONS, ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, GREP_SHAPE, PATTERN_VERBS, PATTERN_VERB_NAMES, GREP_FILE_OPERANDS, READER_VALUE_LETTERS, FILE_OPERAND_FLAGS, SCP_VALUE_FLAGS, TAR_VALUE_LETTERS, ZIP_VALUE_LETTERS, RSYNC_VALUE_LETTERS, RSYNC_SKIP, CP_VALUE_LETTERS, INSTALL_VALUE_LETTERS, COPY_VERBS, TAR_MODE_WORD, COPY_VERB_HEADS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, COMMAND_WRAPPERS, INLINE_INTERPRETER, RUNNER_WRAPPERS, WRAPPER_TAKES_TARGET, FIND_EXEC_FLAGS, FS_OP_CACHE_MAX, fsOpCache, REDIR_TRUNCATE_OPS, REDIR_FILE_IN_OPS, REDIR_HEREDOC_OPS, FIND_OPTIONS, COPY_RULE_OF, isReaderWord, positionalAfter, NONE, UNKNOWN, SSRF_MAX_HOST, METADATA_ADDRESSES, METADATA_HOSTNAMES, v4Octets, SOURCE_COMMANDS, TERMINAL_ESCAPE_RE, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, CANARY_MIN_LENGTH, MAX_TEXT, MAX_DEPTH2, MAX_JSON_PARSE, URL_DEPTH, B64_DEPTH, MIN_SEGMENT, SEPARATORS, stripSeparators, looksText, CANARY_DECODERS, VIEWS, LONG_OUTPUT_THRESHOLD_BYTES;
|
|
1948
1948
|
var init_dist = __esm({
|
|
1949
1949
|
"packages/policy-engine/dist/index.mjs"() {
|
|
1950
1950
|
"use strict";
|
|
@@ -3136,7 +3136,6 @@ var init_dist = __esm({
|
|
|
3136
3136
|
positionalAfter = (words, from, to = words.length) => positionedArgs(words, from, to).map((a) => a.value);
|
|
3137
3137
|
NONE = { kind: "none" };
|
|
3138
3138
|
UNKNOWN = { kind: "unknown" };
|
|
3139
|
-
SOURCE_COMMANDS = /* @__PURE__ */ new Set([...FS_READ_TOOLS, "tee"]);
|
|
3140
3139
|
SSRF_MAX_HOST = 253;
|
|
3141
3140
|
METADATA_ADDRESSES = /* @__PURE__ */ new Set([
|
|
3142
3141
|
"169.254.169.254",
|
|
@@ -3158,6 +3157,7 @@ var init_dist = __esm({
|
|
|
3158
3157
|
const p = a.split(".");
|
|
3159
3158
|
return p.length === 4 ? p.map(Number) : null;
|
|
3160
3159
|
};
|
|
3160
|
+
SOURCE_COMMANDS = /* @__PURE__ */ new Set([...FS_READ_TOOLS, "tee"]);
|
|
3161
3161
|
TERMINAL_ESCAPE_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-_]|[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
3162
3162
|
aws_default = {
|
|
3163
3163
|
name: "aws",
|