@wrongstack/tools 0.298.0 → 0.298.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/builtin.js CHANGED
@@ -16042,6 +16042,48 @@ var RULES = [
16042
16042
  return args.some((a) => /^[0-7]{3,4}$/.test(a) && /7/.test(a));
16043
16043
  },
16044
16044
  reason: "chmod with world-writable octal mode (e.g. 777)"
16045
+ },
16046
+ // ----- network recon / offensive scanners (caution) -----
16047
+ // These tools are purpose-built for network reconnaissance and offensive
16048
+ // security. They have legitimate uses in dev (security testing, infra
16049
+ // debugging) but their presence in an agent's command stream is worth a
16050
+ // caution banner so the user can notice an unexpected scan.
16051
+ {
16052
+ id: "network-scanner",
16053
+ level: "caution",
16054
+ test: (cmd) => cmd === "nmap" || cmd === "masscan" || cmd === "zmap" || cmd === "nuclei" || cmd === "hping3" || cmd === "naabu" || cmd === "katana" || cmd === "amass" || cmd === "subfinder" || cmd === "httpx" || cmd === "rustscan" || cmd === "zgrab",
16055
+ reason: "network scanner / offensive reconnaissance tool"
16056
+ },
16057
+ // ----- process termination (caution) -----
16058
+ // kill/killall/pkill terminate processes. The exec kill guard
16059
+ // (exec-kill-guard.ts) hard-blocks attempts on protected WrongStack
16060
+ // processes; this rule adds a caution banner for generic process
16061
+ // termination so the user sees a warning even for non-protected targets.
16062
+ {
16063
+ id: "process-kill",
16064
+ level: "caution",
16065
+ test: (cmd) => cmd === "kill" || cmd === "killall" || cmd === "pkill",
16066
+ reason: "process termination command"
16067
+ },
16068
+ // ----- shell/interpreter launchers (caution) -----
16069
+ // `env bash -c '…'`, `timeout sh`, `nohup perl -e '…'` etc. wrap a child
16070
+ // binary that bypasses the allowlist name-gate entirely (the wrapper
16071
+ // resolves the child from PATH, not from the allowlist). We flag caution
16072
+ // when a known launcher has a shell/interpreter as its target program.
16073
+ {
16074
+ id: "shell-launcher",
16075
+ level: "caution",
16076
+ test: (cmd, args) => {
16077
+ const launchers = ["env", "timeout", "nohup", "nice", "script", "expect", "tmux", "screen", "byobu", "dtach"];
16078
+ if (!launchers.includes(cmd)) return false;
16079
+ const shells = ["sh", "bash", "zsh", "fish", "python", "python3", "perl", "ruby", "node", "pwsh", "powershell", "cmd"];
16080
+ if (cmd === "env") {
16081
+ const prog = args.find((a) => !a.includes("=") && !a.startsWith("-"));
16082
+ return prog !== void 0 && shells.includes(prog);
16083
+ }
16084
+ return args.some((a) => shells.includes(a));
16085
+ },
16086
+ reason: "launcher wrapping a shell/interpreter (bypasses allowlist name-gate)"
16045
16087
  }
16046
16088
  ];
16047
16089
  function detectDanger(cmd, args, bypass) {
@@ -16313,9 +16355,7 @@ async function checkKillTarget(target) {
16313
16355
  return { blocked: false };
16314
16356
  }
16315
16357
 
16316
- // src/exec.ts
16317
- init_process_registry();
16318
- var isWin4 = process.platform === "win32";
16358
+ // src/exec-allowlist.ts
16319
16359
  var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16320
16360
  // JS / TS toolchain
16321
16361
  "node",
@@ -16394,7 +16434,11 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16394
16434
  "docker",
16395
16435
  "podman",
16396
16436
  "kubectl",
16397
- // network (read-only intent; destructive ops still blocked by BLOCKED_ARG_PATTERNS)
16437
+ // network fetch tools. Per-arg safety is NOT enforced by BLOCKED_ARG_PATTERNS
16438
+ // (no curl/wget entries) — the real boundary is the per-call `confirm`
16439
+ // permission gate (exec.ts permission:'confirm', subjectKey:'command'),
16440
+ // the `pipe-to-shell` danger rule, and the kill guard. The allowlist is a
16441
+ // guidance layer, not a security boundary on its own.
16398
16442
  "curl",
16399
16443
  "wget",
16400
16444
  // common POSIX file/text utilities
@@ -16447,9 +16491,15 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16447
16491
  "powershell.exe",
16448
16492
  "pwsh",
16449
16493
  "pwsh.exe",
16450
- // [core] Extended default allowlist (added 4b3d18d1 + this commit). All
16451
- // non-destructive, broadly-used dev binaries. Per-arg safety is still
16452
- // enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts.
16494
+ // [core] Extended default allowlist (added 4b3d18d1 + this commit). Broadly
16495
+ // used dev binaries — NOT all non-destructive: this section contains
16496
+ // process/system tools (kill, chown, mount, userdel), network scanners
16497
+ // (nmap, masscan, zmap, nuclei), and launchers (env, perl, timeout, tmux).
16498
+ // The real safety boundary for these is the per-call `confirm` permission
16499
+ // gate (exec.ts permission:'confirm', subjectKey:'command' renders the full
16500
+ // invocation) plus the danger rules in _danger-detect.ts. Per-arg hard-deny
16501
+ // is still enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts, but only
16502
+ // for the commands that have entries there (git, find, rm).
16453
16503
  // --- Archives & compression ---
16454
16504
  "7z",
16455
16505
  "7za",
@@ -16621,10 +16671,7 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16621
16671
  "git-lfs",
16622
16672
  "tig",
16623
16673
  "lazygit",
16624
- // --- POSIX text utilities (extended; duplicates of pwd/ls/cat/head/tail/wc/
16625
- // grep/find/echo/awk/mkdir/cp/mv/rm/touch from the base list above are
16626
- // omitted — the Set is de-duplicated at runtime but a clean literal is
16627
- // easier to maintain) ---
16674
+ // --- POSIX text utilities (extended) ---
16628
16675
  "gawk",
16629
16676
  "tr",
16630
16677
  "cut",
@@ -16657,39 +16704,16 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16657
16704
  "locate",
16658
16705
  "which",
16659
16706
  "whereis",
16660
- "type",
16661
- "hash",
16662
- "pushd",
16663
- "popd",
16664
- "dirs",
16665
- "history",
16666
- "fc",
16667
- "jobs",
16668
- "bg",
16669
- "fg",
16670
- "wait",
16671
- "ulimit",
16672
- "umask",
16707
+ // NOTE: shell builtins with no standalone binary (type, hash, pushd,
16708
+ // popd, dirs, history, fc, jobs, bg, fg, wait, ulimit, umask, trap,
16709
+ // exit, return, source, ., alias, unalias, set, unset, export, readonly,
16710
+ // typeset, declare, local, eval, exec) are intentionally excluded —
16711
+ // spawn() would fail with ENOENT on every platform because they only
16712
+ // exist inside a shell process. Use the `bash` tool for builtins.
16673
16713
  "nice",
16674
16714
  "nohup",
16675
16715
  "timeout",
16676
16716
  "time",
16677
- "trap",
16678
- "exit",
16679
- "return",
16680
- "source",
16681
- ".",
16682
- "alias",
16683
- "unalias",
16684
- "set",
16685
- "unset",
16686
- "export",
16687
- "readonly",
16688
- "typeset",
16689
- "declare",
16690
- "local",
16691
- "eval",
16692
- "exec",
16693
16717
  // --- Process / system inspection ---
16694
16718
  "htop",
16695
16719
  "top",
@@ -16920,6 +16944,10 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16920
16944
  "sublert",
16921
16945
  "chaos"
16922
16946
  ]);
16947
+
16948
+ // src/exec.ts
16949
+ init_process_registry();
16950
+ var isWin4 = process.platform === "win32";
16923
16951
  var allowedCommands = new Set(DEFAULT_ALLOWED_COMMANDS);
16924
16952
  var normalizeCmd = (c) => c.trim();
16925
16953
  var dangerBypass = /* @__PURE__ */ new Set();
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Default allowlist of command NAMES the `exec` tool may run.
3
+ *
4
+ * Extracted from exec.ts for auditability. Only the command name is gated
5
+ * (per-arg safety is the BLOCKED_ARG_PATTERNS denylist in exec.ts + the
6
+ * per-call `confirm` permission). A prior version mapped each command to an
7
+ * allowed-args array, but those arrays were never enforced (dead code) — a
8
+ * plain Set is the honest shape.
9
+ *
10
+ * Extend/trim at runtime via `configureExecPolicy()` (wired from
11
+ * `config.tools.exec.{allow,deny}` at boot). `allow` is trusted-config-only;
12
+ * see the security note on ExecToolConfig.
13
+ */
14
+ export declare const DEFAULT_ALLOWED_COMMANDS: ReadonlySet<string>;
15
+ //# sourceMappingURL=exec-allowlist.d.ts.map
package/dist/exec.js CHANGED
@@ -257,6 +257,48 @@ var RULES = [
257
257
  return args.some((a) => /^[0-7]{3,4}$/.test(a) && /7/.test(a));
258
258
  },
259
259
  reason: "chmod with world-writable octal mode (e.g. 777)"
260
+ },
261
+ // ----- network recon / offensive scanners (caution) -----
262
+ // These tools are purpose-built for network reconnaissance and offensive
263
+ // security. They have legitimate uses in dev (security testing, infra
264
+ // debugging) but their presence in an agent's command stream is worth a
265
+ // caution banner so the user can notice an unexpected scan.
266
+ {
267
+ id: "network-scanner",
268
+ level: "caution",
269
+ test: (cmd) => cmd === "nmap" || cmd === "masscan" || cmd === "zmap" || cmd === "nuclei" || cmd === "hping3" || cmd === "naabu" || cmd === "katana" || cmd === "amass" || cmd === "subfinder" || cmd === "httpx" || cmd === "rustscan" || cmd === "zgrab",
270
+ reason: "network scanner / offensive reconnaissance tool"
271
+ },
272
+ // ----- process termination (caution) -----
273
+ // kill/killall/pkill terminate processes. The exec kill guard
274
+ // (exec-kill-guard.ts) hard-blocks attempts on protected WrongStack
275
+ // processes; this rule adds a caution banner for generic process
276
+ // termination so the user sees a warning even for non-protected targets.
277
+ {
278
+ id: "process-kill",
279
+ level: "caution",
280
+ test: (cmd) => cmd === "kill" || cmd === "killall" || cmd === "pkill",
281
+ reason: "process termination command"
282
+ },
283
+ // ----- shell/interpreter launchers (caution) -----
284
+ // `env bash -c '…'`, `timeout sh`, `nohup perl -e '…'` etc. wrap a child
285
+ // binary that bypasses the allowlist name-gate entirely (the wrapper
286
+ // resolves the child from PATH, not from the allowlist). We flag caution
287
+ // when a known launcher has a shell/interpreter as its target program.
288
+ {
289
+ id: "shell-launcher",
290
+ level: "caution",
291
+ test: (cmd, args) => {
292
+ const launchers = ["env", "timeout", "nohup", "nice", "script", "expect", "tmux", "screen", "byobu", "dtach"];
293
+ if (!launchers.includes(cmd)) return false;
294
+ const shells = ["sh", "bash", "zsh", "fish", "python", "python3", "perl", "ruby", "node", "pwsh", "powershell", "cmd"];
295
+ if (cmd === "env") {
296
+ const prog = args.find((a) => !a.includes("=") && !a.startsWith("-"));
297
+ return prog !== void 0 && shells.includes(prog);
298
+ }
299
+ return args.some((a) => shells.includes(a));
300
+ },
301
+ reason: "launcher wrapping a shell/interpreter (bypasses allowlist name-gate)"
260
302
  }
261
303
  ];
262
304
  function detectDanger(cmd, args, bypass) {
@@ -1922,8 +1964,7 @@ async function checkKillTarget(target) {
1922
1964
  return { blocked: false };
1923
1965
  }
1924
1966
 
1925
- // src/exec.ts
1926
- var isWin2 = process.platform === "win32";
1967
+ // src/exec-allowlist.ts
1927
1968
  var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
1928
1969
  // JS / TS toolchain
1929
1970
  "node",
@@ -2002,7 +2043,11 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
2002
2043
  "docker",
2003
2044
  "podman",
2004
2045
  "kubectl",
2005
- // network (read-only intent; destructive ops still blocked by BLOCKED_ARG_PATTERNS)
2046
+ // network fetch tools. Per-arg safety is NOT enforced by BLOCKED_ARG_PATTERNS
2047
+ // (no curl/wget entries) — the real boundary is the per-call `confirm`
2048
+ // permission gate (exec.ts permission:'confirm', subjectKey:'command'),
2049
+ // the `pipe-to-shell` danger rule, and the kill guard. The allowlist is a
2050
+ // guidance layer, not a security boundary on its own.
2006
2051
  "curl",
2007
2052
  "wget",
2008
2053
  // common POSIX file/text utilities
@@ -2055,9 +2100,15 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
2055
2100
  "powershell.exe",
2056
2101
  "pwsh",
2057
2102
  "pwsh.exe",
2058
- // [core] Extended default allowlist (added 4b3d18d1 + this commit). All
2059
- // non-destructive, broadly-used dev binaries. Per-arg safety is still
2060
- // enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts.
2103
+ // [core] Extended default allowlist (added 4b3d18d1 + this commit). Broadly
2104
+ // used dev binaries — NOT all non-destructive: this section contains
2105
+ // process/system tools (kill, chown, mount, userdel), network scanners
2106
+ // (nmap, masscan, zmap, nuclei), and launchers (env, perl, timeout, tmux).
2107
+ // The real safety boundary for these is the per-call `confirm` permission
2108
+ // gate (exec.ts permission:'confirm', subjectKey:'command' renders the full
2109
+ // invocation) plus the danger rules in _danger-detect.ts. Per-arg hard-deny
2110
+ // is still enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts, but only
2111
+ // for the commands that have entries there (git, find, rm).
2061
2112
  // --- Archives & compression ---
2062
2113
  "7z",
2063
2114
  "7za",
@@ -2229,10 +2280,7 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
2229
2280
  "git-lfs",
2230
2281
  "tig",
2231
2282
  "lazygit",
2232
- // --- POSIX text utilities (extended; duplicates of pwd/ls/cat/head/tail/wc/
2233
- // grep/find/echo/awk/mkdir/cp/mv/rm/touch from the base list above are
2234
- // omitted — the Set is de-duplicated at runtime but a clean literal is
2235
- // easier to maintain) ---
2283
+ // --- POSIX text utilities (extended) ---
2236
2284
  "gawk",
2237
2285
  "tr",
2238
2286
  "cut",
@@ -2265,39 +2313,16 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
2265
2313
  "locate",
2266
2314
  "which",
2267
2315
  "whereis",
2268
- "type",
2269
- "hash",
2270
- "pushd",
2271
- "popd",
2272
- "dirs",
2273
- "history",
2274
- "fc",
2275
- "jobs",
2276
- "bg",
2277
- "fg",
2278
- "wait",
2279
- "ulimit",
2280
- "umask",
2316
+ // NOTE: shell builtins with no standalone binary (type, hash, pushd,
2317
+ // popd, dirs, history, fc, jobs, bg, fg, wait, ulimit, umask, trap,
2318
+ // exit, return, source, ., alias, unalias, set, unset, export, readonly,
2319
+ // typeset, declare, local, eval, exec) are intentionally excluded —
2320
+ // spawn() would fail with ENOENT on every platform because they only
2321
+ // exist inside a shell process. Use the `bash` tool for builtins.
2281
2322
  "nice",
2282
2323
  "nohup",
2283
2324
  "timeout",
2284
2325
  "time",
2285
- "trap",
2286
- "exit",
2287
- "return",
2288
- "source",
2289
- ".",
2290
- "alias",
2291
- "unalias",
2292
- "set",
2293
- "unset",
2294
- "export",
2295
- "readonly",
2296
- "typeset",
2297
- "declare",
2298
- "local",
2299
- "eval",
2300
- "exec",
2301
2326
  // --- Process / system inspection ---
2302
2327
  "htop",
2303
2328
  "top",
@@ -2528,6 +2553,9 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
2528
2553
  "sublert",
2529
2554
  "chaos"
2530
2555
  ]);
2556
+
2557
+ // src/exec.ts
2558
+ var isWin2 = process.platform === "win32";
2531
2559
  var allowedCommands = new Set(DEFAULT_ALLOWED_COMMANDS);
2532
2560
  var normalizeCmd = (c) => c.trim();
2533
2561
  function configureExecPolicy(opts = {}) {
package/dist/index.js CHANGED
@@ -7148,6 +7148,48 @@ var RULES = [
7148
7148
  return args.some((a) => /^[0-7]{3,4}$/.test(a) && /7/.test(a));
7149
7149
  },
7150
7150
  reason: "chmod with world-writable octal mode (e.g. 777)"
7151
+ },
7152
+ // ----- network recon / offensive scanners (caution) -----
7153
+ // These tools are purpose-built for network reconnaissance and offensive
7154
+ // security. They have legitimate uses in dev (security testing, infra
7155
+ // debugging) but their presence in an agent's command stream is worth a
7156
+ // caution banner so the user can notice an unexpected scan.
7157
+ {
7158
+ id: "network-scanner",
7159
+ level: "caution",
7160
+ test: (cmd) => cmd === "nmap" || cmd === "masscan" || cmd === "zmap" || cmd === "nuclei" || cmd === "hping3" || cmd === "naabu" || cmd === "katana" || cmd === "amass" || cmd === "subfinder" || cmd === "httpx" || cmd === "rustscan" || cmd === "zgrab",
7161
+ reason: "network scanner / offensive reconnaissance tool"
7162
+ },
7163
+ // ----- process termination (caution) -----
7164
+ // kill/killall/pkill terminate processes. The exec kill guard
7165
+ // (exec-kill-guard.ts) hard-blocks attempts on protected WrongStack
7166
+ // processes; this rule adds a caution banner for generic process
7167
+ // termination so the user sees a warning even for non-protected targets.
7168
+ {
7169
+ id: "process-kill",
7170
+ level: "caution",
7171
+ test: (cmd) => cmd === "kill" || cmd === "killall" || cmd === "pkill",
7172
+ reason: "process termination command"
7173
+ },
7174
+ // ----- shell/interpreter launchers (caution) -----
7175
+ // `env bash -c '…'`, `timeout sh`, `nohup perl -e '…'` etc. wrap a child
7176
+ // binary that bypasses the allowlist name-gate entirely (the wrapper
7177
+ // resolves the child from PATH, not from the allowlist). We flag caution
7178
+ // when a known launcher has a shell/interpreter as its target program.
7179
+ {
7180
+ id: "shell-launcher",
7181
+ level: "caution",
7182
+ test: (cmd, args) => {
7183
+ const launchers = ["env", "timeout", "nohup", "nice", "script", "expect", "tmux", "screen", "byobu", "dtach"];
7184
+ if (!launchers.includes(cmd)) return false;
7185
+ const shells = ["sh", "bash", "zsh", "fish", "python", "python3", "perl", "ruby", "node", "pwsh", "powershell", "cmd"];
7186
+ if (cmd === "env") {
7187
+ const prog = args.find((a) => !a.includes("=") && !a.startsWith("-"));
7188
+ return prog !== void 0 && shells.includes(prog);
7189
+ }
7190
+ return args.some((a) => shells.includes(a));
7191
+ },
7192
+ reason: "launcher wrapping a shell/interpreter (bypasses allowlist name-gate)"
7151
7193
  }
7152
7194
  ];
7153
7195
  function detectDanger(cmd, args, bypass) {
@@ -16535,9 +16577,7 @@ async function checkKillTarget(target) {
16535
16577
  return { blocked: false };
16536
16578
  }
16537
16579
 
16538
- // src/exec.ts
16539
- init_process_registry();
16540
- var isWin4 = process.platform === "win32";
16580
+ // src/exec-allowlist.ts
16541
16581
  var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16542
16582
  // JS / TS toolchain
16543
16583
  "node",
@@ -16616,7 +16656,11 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16616
16656
  "docker",
16617
16657
  "podman",
16618
16658
  "kubectl",
16619
- // network (read-only intent; destructive ops still blocked by BLOCKED_ARG_PATTERNS)
16659
+ // network fetch tools. Per-arg safety is NOT enforced by BLOCKED_ARG_PATTERNS
16660
+ // (no curl/wget entries) — the real boundary is the per-call `confirm`
16661
+ // permission gate (exec.ts permission:'confirm', subjectKey:'command'),
16662
+ // the `pipe-to-shell` danger rule, and the kill guard. The allowlist is a
16663
+ // guidance layer, not a security boundary on its own.
16620
16664
  "curl",
16621
16665
  "wget",
16622
16666
  // common POSIX file/text utilities
@@ -16669,9 +16713,15 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16669
16713
  "powershell.exe",
16670
16714
  "pwsh",
16671
16715
  "pwsh.exe",
16672
- // [core] Extended default allowlist (added 4b3d18d1 + this commit). All
16673
- // non-destructive, broadly-used dev binaries. Per-arg safety is still
16674
- // enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts.
16716
+ // [core] Extended default allowlist (added 4b3d18d1 + this commit). Broadly
16717
+ // used dev binaries — NOT all non-destructive: this section contains
16718
+ // process/system tools (kill, chown, mount, userdel), network scanners
16719
+ // (nmap, masscan, zmap, nuclei), and launchers (env, perl, timeout, tmux).
16720
+ // The real safety boundary for these is the per-call `confirm` permission
16721
+ // gate (exec.ts permission:'confirm', subjectKey:'command' renders the full
16722
+ // invocation) plus the danger rules in _danger-detect.ts. Per-arg hard-deny
16723
+ // is still enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts, but only
16724
+ // for the commands that have entries there (git, find, rm).
16675
16725
  // --- Archives & compression ---
16676
16726
  "7z",
16677
16727
  "7za",
@@ -16843,10 +16893,7 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16843
16893
  "git-lfs",
16844
16894
  "tig",
16845
16895
  "lazygit",
16846
- // --- POSIX text utilities (extended; duplicates of pwd/ls/cat/head/tail/wc/
16847
- // grep/find/echo/awk/mkdir/cp/mv/rm/touch from the base list above are
16848
- // omitted — the Set is de-duplicated at runtime but a clean literal is
16849
- // easier to maintain) ---
16896
+ // --- POSIX text utilities (extended) ---
16850
16897
  "gawk",
16851
16898
  "tr",
16852
16899
  "cut",
@@ -16879,39 +16926,16 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16879
16926
  "locate",
16880
16927
  "which",
16881
16928
  "whereis",
16882
- "type",
16883
- "hash",
16884
- "pushd",
16885
- "popd",
16886
- "dirs",
16887
- "history",
16888
- "fc",
16889
- "jobs",
16890
- "bg",
16891
- "fg",
16892
- "wait",
16893
- "ulimit",
16894
- "umask",
16929
+ // NOTE: shell builtins with no standalone binary (type, hash, pushd,
16930
+ // popd, dirs, history, fc, jobs, bg, fg, wait, ulimit, umask, trap,
16931
+ // exit, return, source, ., alias, unalias, set, unset, export, readonly,
16932
+ // typeset, declare, local, eval, exec) are intentionally excluded —
16933
+ // spawn() would fail with ENOENT on every platform because they only
16934
+ // exist inside a shell process. Use the `bash` tool for builtins.
16895
16935
  "nice",
16896
16936
  "nohup",
16897
16937
  "timeout",
16898
16938
  "time",
16899
- "trap",
16900
- "exit",
16901
- "return",
16902
- "source",
16903
- ".",
16904
- "alias",
16905
- "unalias",
16906
- "set",
16907
- "unset",
16908
- "export",
16909
- "readonly",
16910
- "typeset",
16911
- "declare",
16912
- "local",
16913
- "eval",
16914
- "exec",
16915
16939
  // --- Process / system inspection ---
16916
16940
  "htop",
16917
16941
  "top",
@@ -17142,6 +17166,10 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
17142
17166
  "sublert",
17143
17167
  "chaos"
17144
17168
  ]);
17169
+
17170
+ // src/exec.ts
17171
+ init_process_registry();
17172
+ var isWin4 = process.platform === "win32";
17145
17173
  var allowedCommands = new Set(DEFAULT_ALLOWED_COMMANDS);
17146
17174
  var normalizeCmd = (c) => c.trim();
17147
17175
  function configureExecPolicy(opts = {}) {
package/dist/pack.js CHANGED
@@ -16042,6 +16042,48 @@ var RULES = [
16042
16042
  return args.some((a) => /^[0-7]{3,4}$/.test(a) && /7/.test(a));
16043
16043
  },
16044
16044
  reason: "chmod with world-writable octal mode (e.g. 777)"
16045
+ },
16046
+ // ----- network recon / offensive scanners (caution) -----
16047
+ // These tools are purpose-built for network reconnaissance and offensive
16048
+ // security. They have legitimate uses in dev (security testing, infra
16049
+ // debugging) but their presence in an agent's command stream is worth a
16050
+ // caution banner so the user can notice an unexpected scan.
16051
+ {
16052
+ id: "network-scanner",
16053
+ level: "caution",
16054
+ test: (cmd) => cmd === "nmap" || cmd === "masscan" || cmd === "zmap" || cmd === "nuclei" || cmd === "hping3" || cmd === "naabu" || cmd === "katana" || cmd === "amass" || cmd === "subfinder" || cmd === "httpx" || cmd === "rustscan" || cmd === "zgrab",
16055
+ reason: "network scanner / offensive reconnaissance tool"
16056
+ },
16057
+ // ----- process termination (caution) -----
16058
+ // kill/killall/pkill terminate processes. The exec kill guard
16059
+ // (exec-kill-guard.ts) hard-blocks attempts on protected WrongStack
16060
+ // processes; this rule adds a caution banner for generic process
16061
+ // termination so the user sees a warning even for non-protected targets.
16062
+ {
16063
+ id: "process-kill",
16064
+ level: "caution",
16065
+ test: (cmd) => cmd === "kill" || cmd === "killall" || cmd === "pkill",
16066
+ reason: "process termination command"
16067
+ },
16068
+ // ----- shell/interpreter launchers (caution) -----
16069
+ // `env bash -c '…'`, `timeout sh`, `nohup perl -e '…'` etc. wrap a child
16070
+ // binary that bypasses the allowlist name-gate entirely (the wrapper
16071
+ // resolves the child from PATH, not from the allowlist). We flag caution
16072
+ // when a known launcher has a shell/interpreter as its target program.
16073
+ {
16074
+ id: "shell-launcher",
16075
+ level: "caution",
16076
+ test: (cmd, args) => {
16077
+ const launchers = ["env", "timeout", "nohup", "nice", "script", "expect", "tmux", "screen", "byobu", "dtach"];
16078
+ if (!launchers.includes(cmd)) return false;
16079
+ const shells = ["sh", "bash", "zsh", "fish", "python", "python3", "perl", "ruby", "node", "pwsh", "powershell", "cmd"];
16080
+ if (cmd === "env") {
16081
+ const prog = args.find((a) => !a.includes("=") && !a.startsWith("-"));
16082
+ return prog !== void 0 && shells.includes(prog);
16083
+ }
16084
+ return args.some((a) => shells.includes(a));
16085
+ },
16086
+ reason: "launcher wrapping a shell/interpreter (bypasses allowlist name-gate)"
16045
16087
  }
16046
16088
  ];
16047
16089
  function detectDanger(cmd, args, bypass) {
@@ -16313,9 +16355,7 @@ async function checkKillTarget(target) {
16313
16355
  return { blocked: false };
16314
16356
  }
16315
16357
 
16316
- // src/exec.ts
16317
- init_process_registry();
16318
- var isWin4 = process.platform === "win32";
16358
+ // src/exec-allowlist.ts
16319
16359
  var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16320
16360
  // JS / TS toolchain
16321
16361
  "node",
@@ -16394,7 +16434,11 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16394
16434
  "docker",
16395
16435
  "podman",
16396
16436
  "kubectl",
16397
- // network (read-only intent; destructive ops still blocked by BLOCKED_ARG_PATTERNS)
16437
+ // network fetch tools. Per-arg safety is NOT enforced by BLOCKED_ARG_PATTERNS
16438
+ // (no curl/wget entries) — the real boundary is the per-call `confirm`
16439
+ // permission gate (exec.ts permission:'confirm', subjectKey:'command'),
16440
+ // the `pipe-to-shell` danger rule, and the kill guard. The allowlist is a
16441
+ // guidance layer, not a security boundary on its own.
16398
16442
  "curl",
16399
16443
  "wget",
16400
16444
  // common POSIX file/text utilities
@@ -16447,9 +16491,15 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16447
16491
  "powershell.exe",
16448
16492
  "pwsh",
16449
16493
  "pwsh.exe",
16450
- // [core] Extended default allowlist (added 4b3d18d1 + this commit). All
16451
- // non-destructive, broadly-used dev binaries. Per-arg safety is still
16452
- // enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts.
16494
+ // [core] Extended default allowlist (added 4b3d18d1 + this commit). Broadly
16495
+ // used dev binaries — NOT all non-destructive: this section contains
16496
+ // process/system tools (kill, chown, mount, userdel), network scanners
16497
+ // (nmap, masscan, zmap, nuclei), and launchers (env, perl, timeout, tmux).
16498
+ // The real safety boundary for these is the per-call `confirm` permission
16499
+ // gate (exec.ts permission:'confirm', subjectKey:'command' renders the full
16500
+ // invocation) plus the danger rules in _danger-detect.ts. Per-arg hard-deny
16501
+ // is still enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts, but only
16502
+ // for the commands that have entries there (git, find, rm).
16453
16503
  // --- Archives & compression ---
16454
16504
  "7z",
16455
16505
  "7za",
@@ -16621,10 +16671,7 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16621
16671
  "git-lfs",
16622
16672
  "tig",
16623
16673
  "lazygit",
16624
- // --- POSIX text utilities (extended; duplicates of pwd/ls/cat/head/tail/wc/
16625
- // grep/find/echo/awk/mkdir/cp/mv/rm/touch from the base list above are
16626
- // omitted — the Set is de-duplicated at runtime but a clean literal is
16627
- // easier to maintain) ---
16674
+ // --- POSIX text utilities (extended) ---
16628
16675
  "gawk",
16629
16676
  "tr",
16630
16677
  "cut",
@@ -16657,39 +16704,16 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16657
16704
  "locate",
16658
16705
  "which",
16659
16706
  "whereis",
16660
- "type",
16661
- "hash",
16662
- "pushd",
16663
- "popd",
16664
- "dirs",
16665
- "history",
16666
- "fc",
16667
- "jobs",
16668
- "bg",
16669
- "fg",
16670
- "wait",
16671
- "ulimit",
16672
- "umask",
16707
+ // NOTE: shell builtins with no standalone binary (type, hash, pushd,
16708
+ // popd, dirs, history, fc, jobs, bg, fg, wait, ulimit, umask, trap,
16709
+ // exit, return, source, ., alias, unalias, set, unset, export, readonly,
16710
+ // typeset, declare, local, eval, exec) are intentionally excluded —
16711
+ // spawn() would fail with ENOENT on every platform because they only
16712
+ // exist inside a shell process. Use the `bash` tool for builtins.
16673
16713
  "nice",
16674
16714
  "nohup",
16675
16715
  "timeout",
16676
16716
  "time",
16677
- "trap",
16678
- "exit",
16679
- "return",
16680
- "source",
16681
- ".",
16682
- "alias",
16683
- "unalias",
16684
- "set",
16685
- "unset",
16686
- "export",
16687
- "readonly",
16688
- "typeset",
16689
- "declare",
16690
- "local",
16691
- "eval",
16692
- "exec",
16693
16717
  // --- Process / system inspection ---
16694
16718
  "htop",
16695
16719
  "top",
@@ -16920,6 +16944,10 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16920
16944
  "sublert",
16921
16945
  "chaos"
16922
16946
  ]);
16947
+
16948
+ // src/exec.ts
16949
+ init_process_registry();
16950
+ var isWin4 = process.platform === "win32";
16923
16951
  var allowedCommands = new Set(DEFAULT_ALLOWED_COMMANDS);
16924
16952
  var normalizeCmd = (c) => c.trim();
16925
16953
  var dangerBypass = /* @__PURE__ */ new Set();
package/dist/tool-tier.js CHANGED
@@ -16042,6 +16042,48 @@ var RULES = [
16042
16042
  return args.some((a) => /^[0-7]{3,4}$/.test(a) && /7/.test(a));
16043
16043
  },
16044
16044
  reason: "chmod with world-writable octal mode (e.g. 777)"
16045
+ },
16046
+ // ----- network recon / offensive scanners (caution) -----
16047
+ // These tools are purpose-built for network reconnaissance and offensive
16048
+ // security. They have legitimate uses in dev (security testing, infra
16049
+ // debugging) but their presence in an agent's command stream is worth a
16050
+ // caution banner so the user can notice an unexpected scan.
16051
+ {
16052
+ id: "network-scanner",
16053
+ level: "caution",
16054
+ test: (cmd) => cmd === "nmap" || cmd === "masscan" || cmd === "zmap" || cmd === "nuclei" || cmd === "hping3" || cmd === "naabu" || cmd === "katana" || cmd === "amass" || cmd === "subfinder" || cmd === "httpx" || cmd === "rustscan" || cmd === "zgrab",
16055
+ reason: "network scanner / offensive reconnaissance tool"
16056
+ },
16057
+ // ----- process termination (caution) -----
16058
+ // kill/killall/pkill terminate processes. The exec kill guard
16059
+ // (exec-kill-guard.ts) hard-blocks attempts on protected WrongStack
16060
+ // processes; this rule adds a caution banner for generic process
16061
+ // termination so the user sees a warning even for non-protected targets.
16062
+ {
16063
+ id: "process-kill",
16064
+ level: "caution",
16065
+ test: (cmd) => cmd === "kill" || cmd === "killall" || cmd === "pkill",
16066
+ reason: "process termination command"
16067
+ },
16068
+ // ----- shell/interpreter launchers (caution) -----
16069
+ // `env bash -c '…'`, `timeout sh`, `nohup perl -e '…'` etc. wrap a child
16070
+ // binary that bypasses the allowlist name-gate entirely (the wrapper
16071
+ // resolves the child from PATH, not from the allowlist). We flag caution
16072
+ // when a known launcher has a shell/interpreter as its target program.
16073
+ {
16074
+ id: "shell-launcher",
16075
+ level: "caution",
16076
+ test: (cmd, args) => {
16077
+ const launchers = ["env", "timeout", "nohup", "nice", "script", "expect", "tmux", "screen", "byobu", "dtach"];
16078
+ if (!launchers.includes(cmd)) return false;
16079
+ const shells = ["sh", "bash", "zsh", "fish", "python", "python3", "perl", "ruby", "node", "pwsh", "powershell", "cmd"];
16080
+ if (cmd === "env") {
16081
+ const prog = args.find((a) => !a.includes("=") && !a.startsWith("-"));
16082
+ return prog !== void 0 && shells.includes(prog);
16083
+ }
16084
+ return args.some((a) => shells.includes(a));
16085
+ },
16086
+ reason: "launcher wrapping a shell/interpreter (bypasses allowlist name-gate)"
16045
16087
  }
16046
16088
  ];
16047
16089
  function detectDanger(cmd, args, bypass) {
@@ -16313,9 +16355,7 @@ async function checkKillTarget(target) {
16313
16355
  return { blocked: false };
16314
16356
  }
16315
16357
 
16316
- // src/exec.ts
16317
- init_process_registry();
16318
- var isWin4 = process.platform === "win32";
16358
+ // src/exec-allowlist.ts
16319
16359
  var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16320
16360
  // JS / TS toolchain
16321
16361
  "node",
@@ -16394,7 +16434,11 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16394
16434
  "docker",
16395
16435
  "podman",
16396
16436
  "kubectl",
16397
- // network (read-only intent; destructive ops still blocked by BLOCKED_ARG_PATTERNS)
16437
+ // network fetch tools. Per-arg safety is NOT enforced by BLOCKED_ARG_PATTERNS
16438
+ // (no curl/wget entries) — the real boundary is the per-call `confirm`
16439
+ // permission gate (exec.ts permission:'confirm', subjectKey:'command'),
16440
+ // the `pipe-to-shell` danger rule, and the kill guard. The allowlist is a
16441
+ // guidance layer, not a security boundary on its own.
16398
16442
  "curl",
16399
16443
  "wget",
16400
16444
  // common POSIX file/text utilities
@@ -16447,9 +16491,15 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16447
16491
  "powershell.exe",
16448
16492
  "pwsh",
16449
16493
  "pwsh.exe",
16450
- // [core] Extended default allowlist (added 4b3d18d1 + this commit). All
16451
- // non-destructive, broadly-used dev binaries. Per-arg safety is still
16452
- // enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts.
16494
+ // [core] Extended default allowlist (added 4b3d18d1 + this commit). Broadly
16495
+ // used dev binaries — NOT all non-destructive: this section contains
16496
+ // process/system tools (kill, chown, mount, userdel), network scanners
16497
+ // (nmap, masscan, zmap, nuclei), and launchers (env, perl, timeout, tmux).
16498
+ // The real safety boundary for these is the per-call `confirm` permission
16499
+ // gate (exec.ts permission:'confirm', subjectKey:'command' renders the full
16500
+ // invocation) plus the danger rules in _danger-detect.ts. Per-arg hard-deny
16501
+ // is still enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts, but only
16502
+ // for the commands that have entries there (git, find, rm).
16453
16503
  // --- Archives & compression ---
16454
16504
  "7z",
16455
16505
  "7za",
@@ -16621,10 +16671,7 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16621
16671
  "git-lfs",
16622
16672
  "tig",
16623
16673
  "lazygit",
16624
- // --- POSIX text utilities (extended; duplicates of pwd/ls/cat/head/tail/wc/
16625
- // grep/find/echo/awk/mkdir/cp/mv/rm/touch from the base list above are
16626
- // omitted — the Set is de-duplicated at runtime but a clean literal is
16627
- // easier to maintain) ---
16674
+ // --- POSIX text utilities (extended) ---
16628
16675
  "gawk",
16629
16676
  "tr",
16630
16677
  "cut",
@@ -16657,39 +16704,16 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16657
16704
  "locate",
16658
16705
  "which",
16659
16706
  "whereis",
16660
- "type",
16661
- "hash",
16662
- "pushd",
16663
- "popd",
16664
- "dirs",
16665
- "history",
16666
- "fc",
16667
- "jobs",
16668
- "bg",
16669
- "fg",
16670
- "wait",
16671
- "ulimit",
16672
- "umask",
16707
+ // NOTE: shell builtins with no standalone binary (type, hash, pushd,
16708
+ // popd, dirs, history, fc, jobs, bg, fg, wait, ulimit, umask, trap,
16709
+ // exit, return, source, ., alias, unalias, set, unset, export, readonly,
16710
+ // typeset, declare, local, eval, exec) are intentionally excluded —
16711
+ // spawn() would fail with ENOENT on every platform because they only
16712
+ // exist inside a shell process. Use the `bash` tool for builtins.
16673
16713
  "nice",
16674
16714
  "nohup",
16675
16715
  "timeout",
16676
16716
  "time",
16677
- "trap",
16678
- "exit",
16679
- "return",
16680
- "source",
16681
- ".",
16682
- "alias",
16683
- "unalias",
16684
- "set",
16685
- "unset",
16686
- "export",
16687
- "readonly",
16688
- "typeset",
16689
- "declare",
16690
- "local",
16691
- "eval",
16692
- "exec",
16693
16717
  // --- Process / system inspection ---
16694
16718
  "htop",
16695
16719
  "top",
@@ -16920,6 +16944,10 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
16920
16944
  "sublert",
16921
16945
  "chaos"
16922
16946
  ]);
16947
+
16948
+ // src/exec.ts
16949
+ init_process_registry();
16950
+ var isWin4 = process.platform === "win32";
16923
16951
  var allowedCommands = new Set(DEFAULT_ALLOWED_COMMANDS);
16924
16952
  var normalizeCmd = (c) => c.trim();
16925
16953
  var dangerBypass = /* @__PURE__ */ new Set();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/tools",
3
- "version": "0.298.0",
3
+ "version": "0.298.2",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack built-in tools: read/write/edit, bash/exec, grep/glob, git, fetch, test, lint, and more.",
6
6
  "repository": {
@@ -246,15 +246,15 @@
246
246
  "!dist/**/*.map"
247
247
  ],
248
248
  "dependencies": {
249
- "@playwright/test": "^1.62.0",
249
+ "@playwright/test": "^1.62.1",
250
250
  "@typescript/typescript6": "^6.0.2",
251
251
  "turndown": "^7.2.4",
252
252
  "undici": "^8.9.0",
253
- "@wrongstack/core": "0.298.0",
254
- "@wrongstack/kanban": "0.298.0"
253
+ "@wrongstack/core": "0.298.2",
254
+ "@wrongstack/kanban": "0.298.2"
255
255
  },
256
256
  "devDependencies": {
257
- "@types/node": "^26.1.1",
257
+ "@types/node": "^26.1.2",
258
258
  "typescript": "^7.0.2"
259
259
  },
260
260
  "publishConfig": {