@swestash/agent-lens 0.5.1 → 0.5.2
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/agent-lens.js +61 -15
- package/dist/agent-lens.js.map +1 -1
- package/package.json +1 -1
- package/web/assets/{CopyButton-CAUFwuiX.js → CopyButton-hsiW2B6o.js} +1 -1
- package/web/assets/{Dashboard-5CwsbaWY.js → Dashboard-CPfpfHm8.js} +1 -1
- package/web/assets/{SecurityView-DCWVNFf5.js → SecurityView-CvWWSbuL.js} +1 -1
- package/web/assets/{SessionView-BJywkNAY.js → SessionView-BLTA0iKW.js} +2 -2
- package/web/assets/{SkillView-BDENXN1E.js → SkillView-DVoLJAU0.js} +1 -1
- package/web/assets/{SkillsView-C4SyADuV.js → SkillsView-c6k5JsWR.js} +1 -1
- package/web/assets/{WorkflowView-BQCMn0Uf.js → WorkflowView-juGHkf05.js} +1 -1
- package/web/assets/{index-BR_zJBAm.js → index-BXp9oWUn.js} +1 -1
- package/web/assets/index-BfFCjgfs.css +1 -0
- package/web/assets/{index-dvmn2NT_.js → index-D-kuW17t.js} +2 -2
- package/web/assets/{severity-4pf1WhNq.js → severity-ZaGgvxL_.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-3w3Rb7sW.css +0 -1
package/dist/agent-lens.js
CHANGED
|
@@ -2319,7 +2319,7 @@ function classify(db, dirty) {
|
|
|
2319
2319
|
|
|
2320
2320
|
// ../ingest/dist/detect.js
|
|
2321
2321
|
import { createHash } from "crypto";
|
|
2322
|
-
var DETECTOR_VERSION =
|
|
2322
|
+
var DETECTOR_VERSION = 6;
|
|
2323
2323
|
function evidence(s, max = 200) {
|
|
2324
2324
|
const one = s.replace(/\s+/g, " ").trim();
|
|
2325
2325
|
return one.length > max ? one.slice(0, max - 1) + "\u2026" : one;
|
|
@@ -2381,6 +2381,33 @@ function outsideProject(filePath, projectPath, configDirs) {
|
|
|
2381
2381
|
return false;
|
|
2382
2382
|
return filePath !== projectPath && !filePath.startsWith(projectPath.replace(/\/$/, "") + "/");
|
|
2383
2383
|
}
|
|
2384
|
+
var SCOPE_RANK = { unknown: 0, loopback: 1, internal: 2, external: 3 };
|
|
2385
|
+
function netTargetScope(rawCommand) {
|
|
2386
|
+
const s = rawCommand.replace(/(?:-H|--header)\s+(['"]).*?\1/gi, " ").replace(/(?:-H|--header)\s+[^\s'"]+/gi, " ");
|
|
2387
|
+
const authorities = [];
|
|
2388
|
+
for (const m of s.matchAll(/\bhttps?:\/\/(\[[0-9a-fA-F:]+\]|[^/\s"'<>|]+)/gi))
|
|
2389
|
+
authorities.push(m[1]);
|
|
2390
|
+
for (const m of s.matchAll(/(?:^|[\s"'=(])(\[[0-9a-fA-F:]+\]|[A-Za-z0-9.-]+):\d{2,5}(?=[/\s"']|$)/g))
|
|
2391
|
+
authorities.push(m[1]);
|
|
2392
|
+
let scope = "unknown";
|
|
2393
|
+
for (let host of authorities) {
|
|
2394
|
+
host = host.replace(/^\[|\]$/g, "").replace(/^[^@/]*@/, "").toLowerCase();
|
|
2395
|
+
if (!host.includes("::"))
|
|
2396
|
+
host = host.replace(/:\d+$/, "");
|
|
2397
|
+
let hs;
|
|
2398
|
+
if (host === "localhost" || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host) || host === "0.0.0.0" || host === "::1")
|
|
2399
|
+
hs = "loopback";
|
|
2400
|
+
else if (/^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host) || // RFC1918
|
|
2401
|
+
/^192\.168\.\d{1,3}\.\d{1,3}$/.test(host) || /^172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}$/.test(host) || /^169\.254\.\d{1,3}\.\d{1,3}$/.test(host) || // link-local
|
|
2402
|
+
host.endsWith(".local") || host.endsWith(".internal") || !host.includes("."))
|
|
2403
|
+
hs = "internal";
|
|
2404
|
+
else
|
|
2405
|
+
hs = "external";
|
|
2406
|
+
if (SCOPE_RANK[hs] > SCOPE_RANK[scope])
|
|
2407
|
+
scope = hs;
|
|
2408
|
+
}
|
|
2409
|
+
return scope;
|
|
2410
|
+
}
|
|
2384
2411
|
var RULES = [
|
|
2385
2412
|
// --- Destructive / data-loss (OWASP ASI02 Tool Misuse) -------------------
|
|
2386
2413
|
{
|
|
@@ -2407,7 +2434,8 @@ var RULES = [
|
|
|
2407
2434
|
framework_ref: "OWASP ASI02",
|
|
2408
2435
|
title: "Discards local changes (git reset --hard)",
|
|
2409
2436
|
tools: ["Bash"],
|
|
2410
|
-
baseSeverity: "
|
|
2437
|
+
baseSeverity: "low",
|
|
2438
|
+
// routine dev op — only uncommitted working-tree changes are lost; commits survive in reflog
|
|
2411
2439
|
test(ctx) {
|
|
2412
2440
|
const c = ctx.commandBare;
|
|
2413
2441
|
if (!c || !/\bgit\s+reset\s+--hard\b/i.test(c))
|
|
@@ -2421,13 +2449,14 @@ var RULES = [
|
|
|
2421
2449
|
framework_ref: "OWASP ASI02",
|
|
2422
2450
|
title: "Force-push rewrites remote history",
|
|
2423
2451
|
tools: ["Bash"],
|
|
2424
|
-
baseSeverity: "
|
|
2452
|
+
baseSeverity: "low",
|
|
2453
|
+
// feature-branch force-push is routine; only a protected branch (below) is high
|
|
2425
2454
|
test(ctx) {
|
|
2426
2455
|
const c = ctx.commandBare;
|
|
2427
2456
|
if (!c || !/\bgit\s+push\b[^|;&\n]*(--force\b|--force-with-lease\b|\s-f\b)/i.test(c))
|
|
2428
2457
|
return null;
|
|
2429
2458
|
const mainBranch = /\b(main|master|release)\b/.test(c);
|
|
2430
|
-
return { evidence: evidence(ctx.command), severity: mainBranch ? "high" : "
|
|
2459
|
+
return { evidence: evidence(ctx.command), severity: mainBranch ? "high" : "low", mods: { protected_branch: mainBranch } };
|
|
2431
2460
|
}
|
|
2432
2461
|
},
|
|
2433
2462
|
{
|
|
@@ -2465,14 +2494,16 @@ var RULES = [
|
|
|
2465
2494
|
framework_ref: "OWASP ASI02",
|
|
2466
2495
|
title: "Overwrites a critical project file",
|
|
2467
2496
|
tools: ["Write", "Edit", "MultiEdit"],
|
|
2468
|
-
baseSeverity: "
|
|
2497
|
+
baseSeverity: "low",
|
|
2469
2498
|
test(ctx) {
|
|
2470
2499
|
const f = ctx.filePath;
|
|
2471
2500
|
if (!f)
|
|
2472
2501
|
return null;
|
|
2473
|
-
|
|
2502
|
+
const lock = /(^|\/)(package-lock\.json|pnpm-lock\.ya?ml|yarn\.lock|Cargo\.lock|go\.sum)\b/.test(f);
|
|
2503
|
+
const ci = /(^|\/)(\.github\/workflows\/|\.gitlab-ci\.ya?ml)\b/.test(f);
|
|
2504
|
+
if (!lock && !ci)
|
|
2474
2505
|
return null;
|
|
2475
|
-
return { evidence: evidence(f) };
|
|
2506
|
+
return { evidence: evidence(f), severity: ci ? "medium" : "low", mods: { kind: ci ? "ci-config" : "lockfile" } };
|
|
2476
2507
|
}
|
|
2477
2508
|
},
|
|
2478
2509
|
// --- Credential & secret access ------------------------------------------
|
|
@@ -2540,22 +2571,29 @@ var RULES = [
|
|
|
2540
2571
|
id: "exfil.network_upload",
|
|
2541
2572
|
category: "exfiltration",
|
|
2542
2573
|
framework_ref: "MITRE ATLAS AML.T0086",
|
|
2543
|
-
title: "Uploads data to
|
|
2574
|
+
title: "Uploads data to a network host",
|
|
2544
2575
|
tools: ["Bash"],
|
|
2545
2576
|
baseSeverity: "high",
|
|
2546
2577
|
test(ctx) {
|
|
2547
2578
|
const c = ctx.commandBare;
|
|
2548
2579
|
if (!c)
|
|
2549
2580
|
return null;
|
|
2550
|
-
const upload = /\b(curl|wget)\b[^|;&\n]*(-X\s*POST|--data\b|--data-\w+\b|\s-d\b|-T\b|--upload-file\b|-F\b|--form\b)
|
|
2581
|
+
const upload = /\b(curl|wget)\b[^|;&\n]*(-X\s*POST|--data\b|--data-\w+\b|\s-d\b|-T\b|--upload-file\b|-F\b|--form\b)/.test(c);
|
|
2551
2582
|
if (!upload)
|
|
2552
2583
|
return null;
|
|
2553
|
-
const external = /https?:\/\/(?!(localhost|127\.0\.0\.1|0\.0\.0\.0))/i.test(c);
|
|
2554
2584
|
const withFile = /(@[^\s'"]+|--upload-file|\s-T\b)/.test(c);
|
|
2585
|
+
const scope = netTargetScope(ctx.command);
|
|
2586
|
+
let severity;
|
|
2587
|
+
if (scope === "external")
|
|
2588
|
+
severity = withFile ? "critical" : "high";
|
|
2589
|
+
else if (scope === "unknown")
|
|
2590
|
+
severity = "high";
|
|
2591
|
+
else
|
|
2592
|
+
severity = withFile ? bumpSeverity(scope === "loopback" ? "info" : "low", 1) : scope === "loopback" ? "info" : "low";
|
|
2555
2593
|
return {
|
|
2556
2594
|
evidence: evidence(ctx.command),
|
|
2557
|
-
severity
|
|
2558
|
-
mods: {
|
|
2595
|
+
severity,
|
|
2596
|
+
mods: { target_scope: scope, with_file: withFile }
|
|
2559
2597
|
};
|
|
2560
2598
|
}
|
|
2561
2599
|
},
|
|
@@ -2599,7 +2637,14 @@ var RULES = [
|
|
|
2599
2637
|
baseSeverity: "high",
|
|
2600
2638
|
test(ctx) {
|
|
2601
2639
|
const c = ctx.commandBare;
|
|
2602
|
-
if (!c
|
|
2640
|
+
if (!c)
|
|
2641
|
+
return null;
|
|
2642
|
+
const m = /\b(?:curl|wget)\b[^|]*\|\s*(?:sudo\s+)?(sh|bash|zsh|python\d?|node)\b([^|;&]*)/i.exec(c);
|
|
2643
|
+
if (!m)
|
|
2644
|
+
return null;
|
|
2645
|
+
const interp = m[1].toLowerCase();
|
|
2646
|
+
const args = m[2] || "";
|
|
2647
|
+
if (/^(?:node|python)/.test(interp) && /(?:^|\s)-(?:e|c|m|p)\b|(?:^|\s)--(?:eval|command|module|print)\b/.test(args))
|
|
2603
2648
|
return null;
|
|
2604
2649
|
return { evidence: evidence(ctx.command) };
|
|
2605
2650
|
}
|
|
@@ -2673,13 +2718,14 @@ var RULES = [
|
|
|
2673
2718
|
framework_ref: "OWASP LLM06",
|
|
2674
2719
|
title: "Writes a file outside the working project",
|
|
2675
2720
|
tools: ["Write", "Edit", "MultiEdit"],
|
|
2676
|
-
baseSeverity: "
|
|
2721
|
+
baseSeverity: "low",
|
|
2722
|
+
// writing to /tmp, scratch dirs, adjacent repos is routine; only a system path (below) is high
|
|
2677
2723
|
test(ctx) {
|
|
2678
2724
|
const f = ctx.filePath;
|
|
2679
2725
|
if (!outsideProject(f, ctx.projectPath, ctx.ownedConfigDirs))
|
|
2680
2726
|
return null;
|
|
2681
2727
|
const system = !!f && SYSTEM_PATH.test(f);
|
|
2682
|
-
return { evidence: evidence(f), severity: system ? "high" : "
|
|
2728
|
+
return { evidence: evidence(f), severity: system ? "high" : "low", mods: { project: ctx.projectPath, system_path: system } };
|
|
2683
2729
|
}
|
|
2684
2730
|
}
|
|
2685
2731
|
];
|