@wrongstack/acp 0.287.0 → 0.291.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.
@@ -326,6 +326,23 @@ export declare class ACPSession {
326
326
  private scratch;
327
327
  private resetScratch;
328
328
  private handlePermissionRequest;
329
+ /**
330
+ * Enforce authorization at privileged callback sinks (fs/write,
331
+ * terminal/create). Unlike `handlePermissionRequest` which responds to
332
+ * agent-initiated `session/request_permission` messages, this method is
333
+ * called by the handler BEFORE dispatching to FileServer/TerminalServer,
334
+ * closing the gap where the agent simply skips the voluntary permission
335
+ * request and sends the privileged callback directly.
336
+ *
337
+ * Uses the session's permission policy. The default policy
338
+ * (`defaultPermissionPolicy`) auto-approves everything — this is correct
339
+ * for trusted local agents (CLI `acp spawn`, Director fan-out). For
340
+ * untrusted/remote agents, the host should inject
341
+ * `readOnlyPermissionPolicy` or an interactive policy.
342
+ *
343
+ * Returns true if the callback is authorized, false if denied.
344
+ */
345
+ private authorizeCallback;
329
346
  private handleFsRequest;
330
347
  private handleTerminalRequest;
331
348
  }
@@ -1 +1 @@
1
- {"version":3,"file":"acp-session.d.ts","sourceRoot":"","sources":["../../src/client/acp-session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acp-session.d.ts","sourceRoot":"","sources":["../../src/client/acp-session.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,17 @@ export interface FileServerOptions {
3
3
  projectRoot: string;
4
4
  /** Per-call timeout, default 30s. */
5
5
  timeoutMs?: number;
6
+ /**
7
+ * Hard cap on the number of bytes that may be read in a single
8
+ * `readTextFile` call. Protects against a malicious agent requesting a
9
+ * gigantic file to exhaust host memory. Default 5 MiB.
10
+ */
11
+ maxReadBytes?: number;
12
+ /**
13
+ * Hard cap on the number of bytes that may be written in a single
14
+ * `writeTextFile` call. Default 5 MiB.
15
+ */
16
+ maxWriteBytes?: number;
6
17
  }
7
18
  export interface ReadFileParams {
8
19
  sessionId: string;
@@ -13,7 +24,7 @@ export interface WriteFileParams {
13
24
  path: string;
14
25
  content: string;
15
26
  }
16
- export type FsErrorCode = 'ENOENT' | 'EACCES' | 'OUTSIDE_ROOT' | 'TIMEOUT' | 'INVALID_PATH';
27
+ export type FsErrorCode = 'ENOENT' | 'EACCES' | 'OUTSIDE_ROOT' | 'TIMEOUT' | 'INVALID_PATH' | 'TOO_LARGE';
17
28
  /**
18
29
  * Thrown for protocol-level rejections (path outside root, etc.).
19
30
  * The session converts these into JSON-RPC error responses.
@@ -25,7 +36,10 @@ export declare class FsError extends Error {
25
36
  }
26
37
  export declare class FileServer {
27
38
  private readonly root;
39
+ private readonly realRoot;
28
40
  private readonly timeoutMs;
41
+ private readonly maxReadBytes;
42
+ private readonly maxWriteBytes;
29
43
  constructor(opts: FileServerOptions);
30
44
  /** Read a text file. Returns the content as a string. */
31
45
  readTextFile(params: ReadFileParams): Promise<{
@@ -34,11 +48,19 @@ export declare class FileServer {
34
48
  /** Write a text file. Atomic via write-then-rename. */
35
49
  writeTextFile(params: WriteFileParams): Promise<void>;
36
50
  /**
37
- * Resolve a path; throw `FsError('OUTSIDE_ROOT')` if the result is
38
- * not under the project root. Symlinks are not followed here we
39
- * operate on the textual path. A future hardening pass can
40
- * `fs.realpath` each access to catch symlink escapes.
51
+ * Resolve a path and verify it is inside the project root by realpath.
52
+ * Rejects with `FsError` if the textual path, the resolved path, or the
53
+ * real (symlink-resolved) path escapes the project root.
54
+ *
55
+ * For files that don't exist yet (e.g. a write to a new file), the
56
+ * nearest existing ancestor directory is realpath-checked instead.
41
57
  */
42
58
  private resolveInside;
59
+ /**
60
+ * Resolve `resolvedPath` through `fs.realpath` and verify the result is
61
+ * inside `realRoot`. For non-existent paths (new files), walk up to the
62
+ * nearest existing ancestor and check that instead.
63
+ */
64
+ private assertRealInside;
43
65
  }
44
66
  //# sourceMappingURL=file-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-server.d.ts","sourceRoot":"","sources":["../../src/client/file-server.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,GAAG,SAAS,GAAG,cAAc,CAAC;AAE5F;;;GAGG;AACH,qBAAa,OAAQ,SAAQ,KAAK;IAChC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,YAAY,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAK3D;CACF;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,YAAY,IAAI,EAAE,iBAAiB,EAGlC;IAED,yDAAyD;IACnD,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAkBvE;IAED,uDAAuD;IACjD,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB1D;IAED;;;;;OAKG;IACH,OAAO,CAAC,aAAa;CAetB"}
1
+ {"version":3,"file":"file-server.d.ts","sourceRoot":"","sources":["../../src/client/file-server.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,QAAQ,GACR,cAAc,GACd,SAAS,GACT,cAAc,GACd,WAAW,CAAC;AAKhB;;;GAGG;AACH,qBAAa,OAAQ,SAAQ,KAAK;IAChC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,YAAY,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAK3D;CACF;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC,YAAY,IAAI,EAAE,iBAAiB,EAWlC;IAED,yDAAyD;IACnD,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CA8BvE;IAED,uDAAuD;IACjD,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA4C1D;IAED;;;;;;;OAOG;YACW,aAAa;IAmB3B;;;;OAIG;YACW,gBAAgB;CAwB/B"}
@@ -4,6 +4,13 @@ export interface TerminalServerOptions {
4
4
  commandTimeoutMs?: number;
5
5
  /** Bytes of output to retain per terminal. Default 1 MiB. */
6
6
  outputByteLimit?: number;
7
+ /**
8
+ * Hard maximum cap on the per-call `outputByteLimit`. The agent can request
9
+ * a lower limit per terminal/create, but it can never raise it above this
10
+ * host-configured ceiling. Protects against memory exhaustion from a
11
+ * malicious agent requesting `outputByteLimit: Infinity`. Default 16 MiB.
12
+ */
13
+ maxOutputByteLimit?: number;
7
14
  /** Optional abort signal that kills ALL active terminals. */
8
15
  signal?: AbortSignal;
9
16
  }
@@ -12,6 +19,7 @@ export declare class TerminalServer {
12
19
  private readonly projectRoot;
13
20
  private readonly commandTimeoutMs;
14
21
  private readonly outputByteLimit;
22
+ private readonly maxOutputByteLimit;
15
23
  private nextId;
16
24
  constructor(opts: TerminalServerOptions);
17
25
  /** Spawn a new terminal. Returns the agent-facing id. */
@@ -50,5 +58,12 @@ export declare class TerminalServer {
50
58
  releaseAll(): void;
51
59
  private resolveCwd;
52
60
  private buildEnv;
61
+ /**
62
+ * Clamp an agent-supplied numeric to a finite positive safe integer, falling
63
+ * back to `defaultValue` for undefined/NaN/non-finite values. Prevents
64
+ * negative, NaN, or Infinity values from disabling output caps or causing
65
+ * unbounded memory growth.
66
+ */
67
+ private clampFiniteInt;
53
68
  }
54
69
  //# sourceMappingURL=terminal-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-server.d.ts","sourceRoot":"","sources":["../../src/client/terminal-server.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAoBD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,MAAM,CAAK;IAEnB,YAAY,IAAI,EAAE,qBAAqB,EAOtC;IAED,yDAAyD;IACzD,MAAM,CAAC,MAAM,EAAE;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,GAAG,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACxC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,GAAG;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAgGzB;IAED,iEAAiE;IACjE,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAA;KAAE,CAQlI;IAED,oEAAoE;IAC9D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAIjG;IAED,mFAAmF;IACnF,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAQ7B;IAED,uDAAuD;IACvD,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAahC;IAED,wDAAwD;IACxD,UAAU,IAAI,IAAI,CAIjB;IAED,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,QAAQ;CAuBjB"}
1
+ {"version":3,"file":"terminal-server.d.ts","sourceRoot":"","sources":["../../src/client/terminal-server.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAoBD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,MAAM,CAAK;IAEnB,YAAY,IAAI,EAAE,qBAAqB,EAQtC;IAED,yDAAyD;IACzD,MAAM,CAAC,MAAM,EAAE;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,GAAG,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACxC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,GAAG;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAmGzB;IAED,iEAAiE;IACjE,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAA;KAAE,CAQlI;IAED,oEAAoE;IAC9D,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAIjG;IAED,mFAAmF;IACnF,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAQ7B;IAED,uDAAuD;IACvD,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAahC;IAED,wDAAwD;IACxD,UAAU,IAAI,IAAI,CAIjB;IAED,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,QAAQ;IAwBhB;;;;;OAKG;IACH,OAAO,CAAC,cAAc;CASvB"}
package/dist/client.js CHANGED
@@ -42,7 +42,7 @@ var ClientTransport = class {
42
42
  }
43
43
  async start() {
44
44
  if (this.child) return;
45
- const [{ spawn: spawn2 }, { buildChildEnv }, os] = await Promise.all([
45
+ const [{ spawn: spawn2 }, { buildChildEnv: buildChildEnv2 }, os] = await Promise.all([
46
46
  import("node:child_process"),
47
47
  import("@wrongstack/core"),
48
48
  import("node:os")
@@ -59,7 +59,7 @@ var ClientTransport = class {
59
59
  const childArgs = this.opts.args ?? [];
60
60
  const shim = process.platform === "win32" ? buildWin32CmdShimInvocation(this.opts.command, childArgs) : null;
61
61
  this.child = spawn2(shim?.command ?? this.opts.command, shim?.args ?? childArgs, {
62
- env: { ...buildChildEnv(), ...this.opts.env },
62
+ env: { ...buildChildEnv2(), ...this.opts.env },
63
63
  cwd: spawnCwd,
64
64
  stdio: ["pipe", "pipe", "pipe"],
65
65
  windowsHide: true,
@@ -366,8 +366,12 @@ var ToolTranslator = class {
366
366
  var ACP_PROTOCOL_VERSION = 1;
367
367
 
368
368
  // src/client/file-server.ts
369
+ import { randomBytes } from "node:crypto";
370
+ import { realpathSync } from "node:fs";
369
371
  import * as fsp from "node:fs/promises";
370
372
  import * as path from "node:path";
373
+ var DEFAULT_MAX_READ_BYTES = 5 * 1024 * 1024;
374
+ var DEFAULT_MAX_WRITE_BYTES = 5 * 1024 * 1024;
371
375
  var FsError = class extends Error {
372
376
  code;
373
377
  path;
@@ -380,23 +384,40 @@ var FsError = class extends Error {
380
384
  };
381
385
  var FileServer = class {
382
386
  root;
387
+ realRoot;
383
388
  timeoutMs;
389
+ maxReadBytes;
390
+ maxWriteBytes;
384
391
  constructor(opts) {
385
392
  this.root = path.resolve(opts.projectRoot);
393
+ this.realRoot = safeRealpathSync(this.root);
386
394
  this.timeoutMs = opts.timeoutMs ?? 3e4;
395
+ this.maxReadBytes = opts.maxReadBytes ?? DEFAULT_MAX_READ_BYTES;
396
+ this.maxWriteBytes = opts.maxWriteBytes ?? DEFAULT_MAX_WRITE_BYTES;
387
397
  }
388
398
  /** Read a text file. Returns the content as a string. */
389
399
  async readTextFile(params) {
390
- const safe = this.resolveInside(params.path);
400
+ const safe = await this.resolveInside(params.path);
391
401
  const controller = new AbortController();
392
402
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
393
403
  try {
404
+ const stat2 = await fsp.stat(safe).catch((err) => {
405
+ throw mapFsError(err, safe);
406
+ });
407
+ if (stat2.size > this.maxReadBytes) {
408
+ throw new FsError(
409
+ "TOO_LARGE",
410
+ safe,
411
+ `file is ${stat2.size} bytes, max read is ${this.maxReadBytes} bytes`
412
+ );
413
+ }
394
414
  const content = await fsp.readFile(safe, {
395
415
  encoding: "utf8",
396
416
  signal: controller.signal
397
417
  });
398
418
  return { content };
399
419
  } catch (err) {
420
+ if (err instanceof FsError) throw err;
400
421
  if (controller.signal.aborted) {
401
422
  throw new FsError("TIMEOUT", safe, `readTextFile timed out after ${this.timeoutMs}ms`);
402
423
  }
@@ -407,17 +428,31 @@ var FileServer = class {
407
428
  }
408
429
  /** Write a text file. Atomic via write-then-rename. */
409
430
  async writeTextFile(params) {
410
- const safe = this.resolveInside(params.path);
431
+ const byteLength = Buffer.byteLength(params.content, "utf8");
432
+ if (byteLength > this.maxWriteBytes) {
433
+ throw new FsError(
434
+ "TOO_LARGE",
435
+ params.path,
436
+ `content is ${byteLength} bytes, max write is ${this.maxWriteBytes} bytes`
437
+ );
438
+ }
439
+ const safe = await this.resolveInside(params.path);
411
440
  const controller = new AbortController();
412
441
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
413
- const tmp = `${safe}.${randomHex(4)}.tmp`;
442
+ const tmp = `${safe}.${randomBytes(6).toString("hex")}.tmp`;
414
443
  try {
415
444
  await fsp.writeFile(tmp, params.content, {
416
445
  encoding: "utf8",
417
446
  signal: controller.signal
418
447
  });
448
+ await this.assertRealInside(tmp);
449
+ await this.assertRealInside(path.dirname(safe));
419
450
  await fsp.rename(tmp, safe);
420
451
  } catch (err) {
452
+ if (err instanceof FsError) {
453
+ await fsp.unlink(tmp).catch(() => void 0);
454
+ throw err;
455
+ }
421
456
  try {
422
457
  await fsp.unlink(tmp);
423
458
  } catch {
@@ -431,12 +466,14 @@ var FileServer = class {
431
466
  }
432
467
  }
433
468
  /**
434
- * Resolve a path; throw `FsError('OUTSIDE_ROOT')` if the result is
435
- * not under the project root. Symlinks are not followed here we
436
- * operate on the textual path. A future hardening pass can
437
- * `fs.realpath` each access to catch symlink escapes.
469
+ * Resolve a path and verify it is inside the project root by realpath.
470
+ * Rejects with `FsError` if the textual path, the resolved path, or the
471
+ * real (symlink-resolved) path escapes the project root.
472
+ *
473
+ * For files that don't exist yet (e.g. a write to a new file), the
474
+ * nearest existing ancestor directory is realpath-checked instead.
438
475
  */
439
- resolveInside(p) {
476
+ async resolveInside(p) {
440
477
  if (typeof p !== "string" || p.length === 0) {
441
478
  throw new FsError("INVALID_PATH", p, "path is empty or not a string");
442
479
  }
@@ -448,8 +485,38 @@ var FileServer = class {
448
485
  if (resolved !== this.root && !resolved.startsWith(rootWithSep)) {
449
486
  throw new FsError("OUTSIDE_ROOT", resolved, "path is outside the project root");
450
487
  }
488
+ await this.assertRealInside(resolved);
451
489
  return resolved;
452
490
  }
491
+ /**
492
+ * Resolve `resolvedPath` through `fs.realpath` and verify the result is
493
+ * inside `realRoot`. For non-existent paths (new files), walk up to the
494
+ * nearest existing ancestor and check that instead.
495
+ */
496
+ async assertRealInside(resolvedPath) {
497
+ let probe = resolvedPath;
498
+ for (; ; ) {
499
+ let real;
500
+ try {
501
+ real = await fsp.realpath(probe);
502
+ } catch (err) {
503
+ const code = err.code;
504
+ if (code === "ENOENT") {
505
+ const parent = path.dirname(probe);
506
+ if (parent === probe) return;
507
+ probe = parent;
508
+ continue;
509
+ }
510
+ throw mapFsError(err, resolvedPath);
511
+ }
512
+ if (real === this.realRoot || real.startsWith(this.realRoot + path.sep)) return;
513
+ throw new FsError(
514
+ "OUTSIDE_ROOT",
515
+ resolvedPath,
516
+ "path resolves through a symlink outside the project root"
517
+ );
518
+ }
519
+ }
453
520
  };
454
521
  function mapFsError(err, p) {
455
522
  const code = err?.code;
@@ -460,12 +527,12 @@ function mapFsError(err, p) {
460
527
  const msg = err instanceof Error ? err.message : String(err);
461
528
  return new FsError("INVALID_PATH", p, msg);
462
529
  }
463
- function randomHex(bytes) {
464
- let out = "";
465
- for (let i = 0; i < bytes * 2; i++) {
466
- out += Math.floor(Math.random() * 16).toString(16);
530
+ function safeRealpathSync(p) {
531
+ try {
532
+ return realpathSync(p);
533
+ } catch {
534
+ return p;
467
535
  }
468
- return out;
469
536
  }
470
537
 
471
538
  // src/client/permission.ts
@@ -514,17 +581,21 @@ function makePermissionPolicy(decide) {
514
581
 
515
582
  // src/client/terminal-server.ts
516
583
  import { spawn } from "node:child_process";
584
+ import { realpathSync as realpathSync2 } from "node:fs";
517
585
  import * as path2 from "node:path";
586
+ import { buildChildEnv } from "@wrongstack/core/utils";
518
587
  var TerminalServer = class {
519
588
  terminals = /* @__PURE__ */ new Map();
520
589
  projectRoot;
521
590
  commandTimeoutMs;
522
591
  outputByteLimit;
592
+ maxOutputByteLimit;
523
593
  nextId = 1;
524
594
  constructor(opts) {
525
595
  this.projectRoot = path2.resolve(opts.projectRoot);
526
596
  this.commandTimeoutMs = opts.commandTimeoutMs ?? 5 * 6e4;
527
597
  this.outputByteLimit = opts.outputByteLimit ?? 1024 * 1024;
598
+ this.maxOutputByteLimit = opts.maxOutputByteLimit ?? 16 * 1024 * 1024;
528
599
  if (opts.signal) {
529
600
  opts.signal.addEventListener("abort", () => this.releaseAll());
530
601
  }
@@ -578,12 +649,15 @@ var TerminalServer = class {
578
649
  state.exitStatus = exitStatus;
579
650
  state.output += `[spawn error] ${err.message}
580
651
  `;
581
- state.retainedBytes += Buffer.byteLength(state.output, "utf8");
652
+ state.retainedBytes = Buffer.byteLength(state.output, "utf8");
582
653
  resolve3(exitStatus);
583
654
  });
584
655
  })
585
656
  };
586
- const perCallByteLimit = params.outputByteLimit ?? this.outputByteLimit;
657
+ const perCallByteLimit = Math.min(
658
+ Math.max(1, this.clampFiniteInt(params.outputByteLimit, this.outputByteLimit)),
659
+ this.maxOutputByteLimit
660
+ );
587
661
  proc.stdout?.setEncoding("utf8");
588
662
  proc.stderr?.setEncoding("utf8");
589
663
  const onData = (chunk) => {
@@ -663,24 +737,57 @@ var TerminalServer = class {
663
737
  if (resolved !== this.projectRoot && !resolved.startsWith(rootWithSep)) {
664
738
  return this.projectRoot;
665
739
  }
666
- return resolved;
667
- }
668
- buildEnv(agentEnv) {
669
- const env = { ...process.env };
670
- if (process.platform === "win32") {
671
- if (env.Path !== void 0 && env.PATH === void 0) env.PATH = env.Path;
672
- if (env.PATHEXT !== void 0 && env.PATHEXT_CASE === void 0) {
673
- env.PATHEXT_CASE = env.PATHEXT;
740
+ try {
741
+ const realRoot = realpathSync2(this.projectRoot);
742
+ const realCwd = realpathSync2(resolved);
743
+ const realRootWithSep = realRoot.endsWith(path2.sep) ? realRoot : realRoot + path2.sep;
744
+ if (realCwd !== realRoot && !realCwd.startsWith(realRootWithSep)) {
745
+ return realRoot;
674
746
  }
747
+ return realCwd;
748
+ } catch {
749
+ return this.projectRoot;
675
750
  }
751
+ }
752
+ buildEnv(agentEnv) {
753
+ const env = buildChildEnv();
676
754
  if (agentEnv) {
677
755
  for (const { name, value } of agentEnv) {
756
+ const upper = name.toUpperCase();
757
+ if (DENIED_AGENT_ENV_KEYS.has(upper)) continue;
678
758
  env[name] = value;
679
759
  }
680
760
  }
681
761
  return env;
682
762
  }
763
+ /**
764
+ * Clamp an agent-supplied numeric to a finite positive safe integer, falling
765
+ * back to `defaultValue` for undefined/NaN/non-finite values. Prevents
766
+ * negative, NaN, or Infinity values from disabling output caps or causing
767
+ * unbounded memory growth.
768
+ */
769
+ clampFiniteInt(value, defaultValue) {
770
+ if (value === void 0 || !Number.isFinite(value) || value < 1) {
771
+ return defaultValue;
772
+ }
773
+ return Math.trunc(value);
774
+ }
683
775
  };
776
+ var DENIED_AGENT_ENV_KEYS = /* @__PURE__ */ new Set([
777
+ "NODE_OPTIONS",
778
+ "LD_PRELOAD",
779
+ "LD_LIBRARY_PATH",
780
+ "DYLD_INSERT_LIBRARIES",
781
+ "DYLD_LIBRARY_PATH",
782
+ "DYLD_FALLBACK_LIBRARY_PATH",
783
+ "PATH",
784
+ "PYTHONPATH",
785
+ "PYTHONSTARTUP",
786
+ "PERL5OPT",
787
+ "PERLLIB",
788
+ "RUBYOPT",
789
+ "RUBYLIB"
790
+ ]);
684
791
 
685
792
  // src/client/acp-session.ts
686
793
  var ACPSessionError = class extends Error {
@@ -1542,6 +1649,43 @@ var ACPSession = class _ACPSession {
1542
1649
  await this.sendErrorResponse(id, -32603, `permission policy failed: ${message}`);
1543
1650
  }
1544
1651
  }
1652
+ /**
1653
+ * Enforce authorization at privileged callback sinks (fs/write,
1654
+ * terminal/create). Unlike `handlePermissionRequest` which responds to
1655
+ * agent-initiated `session/request_permission` messages, this method is
1656
+ * called by the handler BEFORE dispatching to FileServer/TerminalServer,
1657
+ * closing the gap where the agent simply skips the voluntary permission
1658
+ * request and sends the privileged callback directly.
1659
+ *
1660
+ * Uses the session's permission policy. The default policy
1661
+ * (`defaultPermissionPolicy`) auto-approves everything — this is correct
1662
+ * for trusted local agents (CLI `acp spawn`, Director fan-out). For
1663
+ * untrusted/remote agents, the host should inject
1664
+ * `readOnlyPermissionPolicy` or an interactive policy.
1665
+ *
1666
+ * Returns true if the callback is authorized, false if denied.
1667
+ */
1668
+ async authorizeCallback(partial) {
1669
+ try {
1670
+ const outcome = await this.permissionPolicy({
1671
+ toolCall: {
1672
+ sessionUpdate: "tool_call_update",
1673
+ toolCallId: partial.toolCallId,
1674
+ title: partial.title,
1675
+ kind: partial.kind,
1676
+ status: "pending"
1677
+ },
1678
+ options: [
1679
+ { optionId: "allow", name: "Allow", kind: "allow_once" },
1680
+ { optionId: "reject", name: "Reject", kind: "reject_once" }
1681
+ ],
1682
+ signal: new AbortController().signal
1683
+ });
1684
+ return outcome.outcome === "selected" && outcome.optionId !== "reject" && outcome.optionId !== "reject_once" && outcome.optionId !== "reject_always";
1685
+ } catch {
1686
+ return false;
1687
+ }
1688
+ }
1545
1689
  async handleFsRequest(msg) {
1546
1690
  const id = msg.id;
1547
1691
  if (id === void 0) return;
@@ -1550,6 +1694,17 @@ var ACPSession = class _ACPSession {
1550
1694
  await this.sendErrorResponse(id, -32602, "path is required");
1551
1695
  return;
1552
1696
  }
1697
+ if (msg.method === "fs/write_text_file") {
1698
+ const allowed = await this.authorizeCallback({
1699
+ toolCallId: `acp-fs-write-${id}`,
1700
+ title: `Write file: ${params.path}`,
1701
+ kind: "edit"
1702
+ });
1703
+ if (!allowed) {
1704
+ await this.sendErrorResponse(id, -32602, "filesystem write denied by permission policy");
1705
+ return;
1706
+ }
1707
+ }
1553
1708
  try {
1554
1709
  if (msg.method === "fs/read_text_file") {
1555
1710
  const result = await this.fileServer.readTextFile({
@@ -1578,6 +1733,15 @@ var ACPSession = class _ACPSession {
1578
1733
  try {
1579
1734
  switch (msg.method) {
1580
1735
  case "terminal/create": {
1736
+ const allowed = await this.authorizeCallback({
1737
+ toolCallId: `acp-terminal-create-${id}`,
1738
+ title: `Run command: ${String(params.command ?? "")} ${(Array.isArray(params.args) ? params.args : []).join(" ")}`.trim(),
1739
+ kind: "execute"
1740
+ });
1741
+ if (!allowed) {
1742
+ await this.sendErrorResponse(id, -32602, "terminal create denied by permission policy");
1743
+ return;
1744
+ }
1581
1745
  const createOpts = {
1582
1746
  sessionId: String(params.sessionId ?? ""),
1583
1747
  command: String(params.command ?? ""),