From 8c6d231dba53ba86b68d32c77e89ec70ce97ddde Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 10 Apr 2026 21:08:35 +0100 Subject: [PATCH] fix(daemon): sanitize launchd handoff label errors --- src/daemon/launchd-restart-handoff.test.ts | 8 ++++---- src/daemon/launchd-restart-handoff.ts | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/daemon/launchd-restart-handoff.test.ts b/src/daemon/launchd-restart-handoff.test.ts index 601e32d10f2..c469308760c 100644 --- a/src/daemon/launchd-restart-handoff.test.ts +++ b/src/daemon/launchd-restart-handoff.test.ts @@ -67,15 +67,15 @@ describe("scheduleDetachedLaunchdRestartHandoff", () => { }); it("rejects invalid launchd labels before spawning the helper", () => { - expect(() => + expect(() => { scheduleDetachedLaunchdRestartHandoff({ env: { HOME: "/Users/test", - OPENCLAW_LAUNCHD_LABEL: "../evil/label", + OPENCLAW_LAUNCHD_LABEL: "../evil/\n\u001b[31mlabel\u001b[0m", }, mode: "kickstart", - }), - ).toThrow("Invalid launchd label"); + }); + }).toThrow("Invalid launchd label: ../evil/label"); expect(spawnMock).not.toHaveBeenCalled(); }); }); diff --git a/src/daemon/launchd-restart-handoff.ts b/src/daemon/launchd-restart-handoff.ts index afb1d3650fc..bae6f156ff5 100644 --- a/src/daemon/launchd-restart-handoff.ts +++ b/src/daemon/launchd-restart-handoff.ts @@ -3,6 +3,7 @@ import os from "node:os"; import path from "node:path"; import { formatErrorMessage } from "../infra/errors.js"; import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { sanitizeForLog } from "../terminal/ansi.js"; import { resolveGatewayLaunchAgentLabel } from "./constants.js"; export type LaunchdRestartHandoffMode = "kickstart" | "start-after-exit"; @@ -23,7 +24,7 @@ export type LaunchdRestartTarget = { function assertValidLaunchAgentLabel(label: string): string { const trimmed = label.trim(); if (!/^[A-Za-z0-9._-]+$/.test(trimmed)) { - throw new Error(`Invalid launchd label: ${trimmed}`); + throw new Error(`Invalid launchd label: ${sanitizeForLog(trimmed)}`); } return trimmed; }