diff --git a/packages/cli/src/__tests__/sprite-cov.test.ts b/packages/cli/src/__tests__/sprite-cov.test.ts index d5bf5136..2d42395d 100644 --- a/packages/cli/src/__tests__/sprite-cov.test.ts +++ b/packages/cli/src/__tests__/sprite-cov.test.ts @@ -488,6 +488,20 @@ describe("sprite/destroyServer", () => { }); }); +// ─── runSprite validation ──────────────────────────────────────────────────── + +describe("sprite/runSprite validation", () => { + it("rejects empty command", async () => { + const { runSprite } = await import("../sprite/sprite"); + await expect(runSprite("")).rejects.toThrow("Invalid command"); + }); + + it("rejects null byte in command", async () => { + const { runSprite } = await import("../sprite/sprite"); + await expect(runSprite("echo\x00hello")).rejects.toThrow("Invalid command"); + }); +}); + // ─── runSprite ─────────────────────────────────────────────────────────────── describe("sprite/runSprite", () => { diff --git a/packages/cli/src/sprite/sprite.ts b/packages/cli/src/sprite/sprite.ts index b0621846..d9232336 100644 --- a/packages/cli/src/sprite/sprite.ts +++ b/packages/cli/src/sprite/sprite.ts @@ -478,6 +478,9 @@ export function getVmConnection(): VMConnection { * Run a command on the remote sprite. Retries on transient errors. */ export async function runSprite(cmd: string, timeoutSecs?: number): Promise { + if (!cmd || /\0/.test(cmd)) { + throw new Error("Invalid command: must be non-empty and must not contain null bytes"); + } const spriteCmd = getSpriteCmd()!; await spriteRetry("sprite exec", async () => { const proc = Bun.spawn( @@ -515,6 +518,9 @@ export async function runSprite(cmd: string, timeoutSecs?: number): Promise { + if (!cmd || /\0/.test(cmd)) { + throw new Error("Invalid command: must be non-empty and must not contain null bytes"); + } const spriteCmd = getSpriteCmd()!; const proc = Bun.spawn( [