Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
5425a78
fix(frontend): add windowsVerbatimArguments for Windows .cmd validation
StillKnotKnown Jan 14, 2026
68cc956
refactor: address PR review feedback
StillKnotKnown Jan 14, 2026
28a69c9
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 14, 2026
a49b683
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 14, 2026
9fae247
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
8af146f
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
4f0d0c3
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
dcd7165
refactor: use top-level type imports for better consistency
StillKnotKnown Jan 15, 2026
140e13a
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
e26b7ac
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
b59cde4
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
08bf443
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
bbbb2f2
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
948f3fa
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
StillKnotKnown Jan 15, 2026
705cac6
Merge branch 'develop' into stillknotknown/acs-252-windows-clicking-c…
AndyMik90 Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/frontend/src/main/cli-tool-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* - Graceful fallbacks when tools not found
*/

import { execFileSync, execFile } from 'child_process';
import { execFileSync, execFile, type ExecFileOptionsWithStringEncoding, type ExecFileSyncOptions } from 'child_process';
import { existsSync, readdirSync, promises as fsPromises } from 'fs';
import path from 'path';
import os from 'os';
Expand All @@ -32,10 +32,10 @@ import { findHomebrewPython as findHomebrewPythonUtil } from './utils/homebrew-p

const execFileAsync = promisify(execFile);

type ExecFileSyncOptionsWithVerbatim = import('child_process').ExecFileSyncOptions & {
export type ExecFileSyncOptionsWithVerbatim = ExecFileSyncOptions & {
windowsVerbatimArguments?: boolean;
};
type ExecFileAsyncOptionsWithVerbatim = import('child_process').ExecFileOptionsWithStringEncoding & {
export type ExecFileAsyncOptionsWithVerbatim = ExecFileOptionsWithStringEncoding & {
windowsVerbatimArguments?: boolean;
};

Expand Down
13 changes: 10 additions & 3 deletions apps/frontend/src/main/ipc-handlers/claude-code-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { promisify } from 'util';
import { IPC_CHANNELS, DEFAULT_APP_SETTINGS } from '../../shared/constants';
import type { IPCResult } from '../../shared/types';
import type { ClaudeCodeVersionInfo, ClaudeInstallationList, ClaudeInstallationInfo } from '../../shared/types/cli';
import { getToolInfo, configureTools, sortNvmVersionDirs, getClaudeDetectionPaths } from '../cli-tool-manager';
import { getToolInfo, configureTools, sortNvmVersionDirs, getClaudeDetectionPaths, type ExecFileAsyncOptionsWithVerbatim } from '../cli-tool-manager';
import { readSettingsFile, writeSettingsFile } from '../settings-utils';
import { isSecurePath } from '../utils/windows-paths';
import semver from 'semver';
Expand All @@ -38,6 +38,11 @@ async function validateClaudeCliAsync(cliPath: string): Promise<[boolean, string
try {
const isWindows = process.platform === 'win32';

// Security validation: reject paths with shell metacharacters or directory traversal
if (isWindows && !isSecurePath(cliPath)) {
throw new Error(`Claude CLI path failed security validation: ${cliPath}`);
}

// Augment PATH with the CLI directory for proper resolution
const cliDir = path.dirname(cliPath);
const env = {
Expand All @@ -56,12 +61,14 @@ async function validateClaudeCliAsync(cliPath: string): Promise<[boolean, string
|| path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'cmd.exe');
// Use double-quoted command line for paths with spaces
const cmdLine = `""${cliPath}" --version"`;
const result = await execFileAsync(cmdExe, ['/d', '/s', '/c', cmdLine], {
const execOptions: ExecFileAsyncOptionsWithVerbatim = {
encoding: 'utf-8',
timeout: 5000,
windowsHide: true,
windowsVerbatimArguments: true,
env,
});
};
const result = await execFileAsync(cmdExe, ['/d', '/s', '/c', cmdLine], execOptions);
stdout = result.stdout;
} else {
const result = await execFileAsync(cliPath, ['--version'], {
Expand Down
Loading