diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000000..b0f84466bf --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2026-05-03 - [Security] Add command safety check to execCommand +**Vulnerability:** Execution of unsecure binaries found in the current directory (binary planting) when using `execCommand`. +**Learning:** Core utility functions for command execution should consistently apply safety checks to prevent PATH-hijacking-like attacks in the current working directory. +**Prevention:** Always use `parseCommand` and `checkCommandSafety` in command execution wrappers to validate the binary location before invoking execution libraries like `execa`. diff --git a/packages/cli-kit/src/public/node/system.test.ts b/packages/cli-kit/src/public/node/system.test.ts index f61a931899..48c638d01c 100644 --- a/packages/cli-kit/src/public/node/system.test.ts +++ b/packages/cli-kit/src/public/node/system.test.ts @@ -266,6 +266,17 @@ describe('execCommand', () => { // Then expect(execaCommand).toHaveBeenCalledWith('cat', expect.objectContaining({stdin: 'inherit'})) }) + + test('raises an error if the command to run is found in the current directory', async () => { + // Given + vi.mocked(which.sync).mockReturnValueOnce('/currentDirectory/command') + + // When + const got = system.execCommand('command', {cwd: '/currentDirectory'}) + + // Then + await expect(got).rejects.toThrowError('Skipped run of unsecure binary command found in the current directory.') + }) }) describe('isStdinPiped', () => { diff --git a/packages/cli-kit/src/public/node/system.ts b/packages/cli-kit/src/public/node/system.ts index a532dce70a..f85ca9b7e8 100644 --- a/packages/cli-kit/src/public/node/system.ts +++ b/packages/cli-kit/src/public/node/system.ts @@ -206,6 +206,10 @@ export async function execCommand(command: string, options?: ExecOptions): Promi env.FORCE_COLOR = '1' } const executionCwd = options?.cwd ?? cwd() + const [cmd] = parseCommand(command) + if (cmd) { + checkCommandSafety(cmd, {cwd: executionCwd}) + } try { await execaCommand(command, { env,