opencode-swarm 7.81.2 → 7.81.3

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/index.js CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "opencode-swarm",
55
- version: "7.81.2",
55
+ version: "7.81.3",
56
56
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
57
57
  main: "dist/index.js",
58
58
  types: "dist/index.d.ts",
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.81.2",
72
+ version: "7.81.3",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -28232,6 +28232,8 @@ class BubblewrapSandboxExecutor {
28232
28232
  "--unshare-ipc",
28233
28233
  "--die-with-parent",
28234
28234
  "--new-session",
28235
+ "--cap-drop",
28236
+ "ALL",
28235
28237
  ...bindArgs,
28236
28238
  "--dev",
28237
28239
  "/dev",
@@ -28528,6 +28530,18 @@ function probeWindowsSandbox() {
28528
28530
  function psStringEscape(s) {
28529
28531
  return s.replace(/[`"$]/g, "`$&");
28530
28532
  }
28533
+ function getSafeWindowsPath() {
28534
+ const raw = process.env.SystemRoot;
28535
+ const isValid = typeof raw === "string" && raw.length > 0 && /^[A-Za-z]:[\\/](?:[^\\/;"'<>|*?\r\n]+[\\/]?)*$/.test(raw);
28536
+ const sysRoot = isValid ? raw : "C:\\Windows";
28537
+ return `${sysRoot}\\System32;${sysRoot}`;
28538
+ }
28539
+ function isPowerShellNativeCommand(command) {
28540
+ return /^(?:Remove-Item|rm|del|erase|Copy-Item|cp|copy|Move-Item|mv|move|Rename-Item|ren|New-Item|ni|Get-Item|gi|Get-ChildItem|ls|dir|gci|Get-Content|cat|type|gc|Set-Content|sc|Add-Content|ac|Clear-Content|clc|Test-Path|Resolve-Path|Split-Path|Join-Path|Out-File|Get-Date)\b/i.test(command.trimStart());
28541
+ }
28542
+ function isSafePsCommandBody(command) {
28543
+ return !/[;&|`$()\r\n]/.test(command);
28544
+ }
28531
28545
  function isPathInScopes(command, scopes) {
28532
28546
  if (scopes.length === 0)
28533
28547
  return true;
@@ -28597,9 +28611,13 @@ class WindowsSandboxExecutor {
28597
28611
  if (!isPathInScopes(command, _allScopes)) {
28598
28612
  throw new SandboxError("Command targets paths outside authorized scopes", "PATH_ESCAPE_SCOPE");
28599
28613
  }
28600
- const safePath = "C:\\Windows\\System32;C:\\Windows";
28614
+ if (isPowerShellNativeCommand(command) && !isSafePsCommandBody(command)) {
28615
+ throw new SandboxError("PowerShell-native command body contains unsafe characters", "UNSAFE_PS_COMMAND");
28616
+ }
28617
+ const safePath = getSafeWindowsPath();
28601
28618
  const escapedTemp = psStringEscape(temp);
28602
28619
  const escapedCommand = psStringEscape(command);
28620
+ const commandExec = isPowerShellNativeCommand(command) ? `Invoke-Expression "${escapedCommand}"` : `cmd /c "${escapedCommand}"`;
28603
28621
  const psScript = `
28604
28622
  $ErrorActionPreference = 'Stop';
28605
28623
  try {
@@ -28626,8 +28644,8 @@ try {
28626
28644
  }
28627
28645
  }
28628
28646
 
28629
- # Execute the command via cmd /c
28630
- cmd /c "${escapedCommand}";
28647
+ # Execute the command — PS-native cmdlets via Invoke-Expression, others via the standard command interpreter
28648
+ ${commandExec};
28631
28649
  } catch {
28632
28650
  Write-Error $_.Exception.Message;
28633
28651
  exit 1;
@@ -28636,7 +28654,7 @@ try {
28636
28654
  }
28637
28655
  getEnvOverrides() {
28638
28656
  return {
28639
- PATH: "C:\\Windows\\System32;C:\\Windows",
28657
+ PATH: getSafeWindowsPath(),
28640
28658
  TEMP: null,
28641
28659
  TMP: null,
28642
28660
  LD_PRELOAD: null,
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Wraps shell commands with bwrap (Bubblewrap) to restrict process capabilities.
5
5
  * Uses --bind to mount scope paths read-write, --tmpfs for /tmp, and --ro-bind
6
- * for essential read-only system paths.
6
+ * for essential read-only system paths. Drops all capabilities via --cap-drop ALL
7
+ * for defense-in-depth within the user namespace.
7
8
  */
8
9
  import { type SandboxExecutor } from '../executor';
9
10
  /**
@@ -1,14 +1,15 @@
1
1
  /**
2
2
  * macOS sandbox-exec sandbox executor.
3
3
  *
4
- * Wraps shell commands with sandbox-exec(8) to restrict process capabilities
5
- * using a profile-based deny-by-default policy.
4
+ * Wraps shell commands with sandbox-exec(8) to enforce file-write containment.
6
5
  *
7
- * Profile allows:
6
+ * Profile scope:
7
+ * - Non-file operations (network, IPC, process creation, sysctl reads) are
8
+ * ALLOWED via `(allow default)`. This executor enforces file-write
9
+ * containment only — it is not a full-process sandbox.
8
10
  * - Read-only access to essential system paths (/usr, /bin, /sbin, /lib)
9
- * - Read-write access to each scope path
10
- * - Read-write access to the temp directory (500MB bounded)
11
- * - Denies all other file writes
11
+ * - Read-write access to each scope path and the temp directory
12
+ * - All other file writes are denied
12
13
  */
13
14
  import { type SandboxExecutor } from '../executor';
14
15
  /**
@@ -73,13 +73,23 @@ export declare class WindowsSandboxExecutor implements SandboxExecutor {
73
73
  * - Sets scoped temp directory (%TEMP%, %TMP%)
74
74
  * - Restricts PATH to safe system paths only
75
75
  * - Removes dangerous environment variables that could be used to bypass restrictions
76
- * - Executes the command via cmd /c inside a PowerShell script
76
+ * - Executes PowerShell-native cmdlets (filesystem cmdlets only) via Invoke-Expression,
77
+ * and all other commands via cmd /c inside a PowerShell script
78
+ *
79
+ * Safety checks applied before wrapping:
80
+ * - PowerShell escape patterns are rejected via detectPowerShellEscape
81
+ * - PowerShell-native commands are restricted to a filesystem-only cmdlet whitelist
82
+ * - PowerShell-native command bodies must not contain statement separators (;),
83
+ * call operator (&), pipelines (|), backtick escapes (`), variable references ($),
84
+ * subexpressions/parentheses, or newlines
77
85
  *
78
86
  * @param command - Raw shell command to execute inside the sandbox
79
87
  * @param scopePaths - Additional scope paths to allow (merged with constructor scope)
80
88
  * @param tempDir - Optional temp directory override
81
89
  * @returns A PowerShell-wrapped command string ready for shell execution,
82
90
  * or the raw command string when the sandbox is unavailable (passthrough mode)
91
+ * @throws {SandboxError} UNSAFE_PS_COMMAND when a PowerShell-native command body
92
+ * contains characters that enable command injection via Invoke-Expression
83
93
  */
84
94
  wrapCommand(command: string, scopePaths: string[], tempDir?: string): string;
85
95
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.81.2",
3
+ "version": "7.81.3",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,89 +0,0 @@
1
- /**
2
- * Edge case handling utilities for Bubblewrap sandbox.
3
- *
4
- * This module provides functions to detect and prevent:
5
- * - Symlink escape attacks
6
- * - /proc/self/fd access
7
- * - io_uring bypass
8
- * - Namespace escape
9
- * - Hard-link creation
10
- * - Rename/move across scope boundary
11
- * - mmap interception
12
- */
13
- /**
14
- * Check whether a path is a symlink and resolves to a location outside
15
- * any of the configured scope paths.
16
- *
17
- * @param path - The path to check (may be a symlink)
18
- * @param scopePaths - Array of absolute scope paths
19
- * @returns true if the path is a symlink that escapes the sandbox
20
- */
21
- export declare function detectSymlinkEscape(path: string, scopePaths: string[]): boolean;
22
- /**
23
- * Check whether a path is under /proc/self/fd/, which provides
24
- * file descriptor access that can bypass normal path checks.
25
- *
26
- * @param path - The path to check
27
- * @returns true if the path is under /proc/self/fd/
28
- */
29
- export declare function detectProcFdAccess(path: string): boolean;
30
- /**
31
- * Detect whether io_uring is active on the system, which can be used
32
- * to perform I/O operations that bypass the seccomp filter.
33
- *
34
- * Note: This is a detection function only — it does not prevent io_uring usage.
35
- * Bubblewrap's --unshare-all combined with seccomp filtering can mitigate this.
36
- *
37
- * @returns true if io_uring appears to be active
38
- */
39
- export declare function detectIoUringBypass(): boolean;
40
- /**
41
- * Detect whether the current process is already running inside a user namespace.
42
- *
43
- * When a process is already inside a user namespace (rather than the initial
44
- * namespace), it may have different privileges and isolation properties than
45
- * expected. This can affect the security assumptions of a bubblewrap sandbox.
46
- *
47
- * @returns true if the current process is already inside a non-initial user namespace
48
- */
49
- export declare function detectNamespaceEscape(): boolean;
50
- /**
51
- * Check whether a path operation would create a hard link that escapes
52
- * the sandbox scope.
53
- *
54
- * Hard links can allow a file inside the sandbox to be linked to a location
55
- * outside the sandbox, potentially bypassing containment.
56
- *
57
- * @param path - The path being linked to
58
- * @param scopePaths - Array of absolute scope paths
59
- * @returns true if creating a hard link at path would escape the sandbox
60
- */
61
- export declare function detectHardLinkEscape(path: string, scopePaths: string[]): boolean;
62
- /**
63
- * Alias for detectHardLinkEscape for API compatibility.
64
- * @param path - The path being linked to
65
- * @param scopePaths - Array of absolute scope paths
66
- * @returns true if creating a hard link at path would escape the sandbox
67
- */
68
- export declare function detectHardLinkCreation(path: string, scopePaths: string[]): boolean;
69
- /**
70
- * Check whether a rename or move operation crosses a scope boundary.
71
- *
72
- * Moving a file from inside a scope path to outside violates containment.
73
- *
74
- * @param oldPath - The original path
75
- * @param newPath - The destination path after rename/move
76
- * @param scopePaths - Array of absolute scope paths
77
- * @returns true if the rename crosses a scope boundary
78
- */
79
- export declare function detectRenameAcrossBoundary(oldPath: string, newPath: string, scopePaths: string[]): boolean;
80
- /**
81
- * Check whether a path pattern suggests mmap interception attempts.
82
- *
83
- * mmap can be used to map device files or anonymous memory that bypasses
84
- * normal file-based access controls.
85
- *
86
- * @param path - The path being accessed
87
- * @returns true if the path suggests mmap interception
88
- */
89
- export declare function detectMmapInterception(path: string): boolean;