Skip to content

Commit 0801aab

Browse files
authored
Merge branch 'develop' into feature/implicit-conflict-detection
2 parents 536ef3b + eeef8a3 commit 0801aab

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

apps/frontend/src/main/claude-profile/profile-utils.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,32 @@ export async function createProfileDirectory(profileName: string): Promise<strin
5656

5757
/**
5858
* Check if a profile has valid authentication
59-
* (checks if the config directory has credential files)
59+
* (checks if the config directory has credential files or OAuth account info)
6060
*/
6161
export function isProfileAuthenticated(profile: ClaudeProfile): boolean {
6262
const configDir = profile.configDir;
6363
if (!configDir || !existsSync(configDir)) {
6464
return false;
6565
}
6666

67-
// Claude stores auth in .claude/credentials or similar files
67+
// Check for .claude.json with OAuth account info (modern Claude Code CLI)
68+
// This is how Claude Code CLI stores OAuth authentication since v1.0
69+
const claudeJsonPath = join(configDir, '.claude.json');
70+
if (existsSync(claudeJsonPath)) {
71+
try {
72+
const content = readFileSync(claudeJsonPath, 'utf-8');
73+
const data = JSON.parse(content);
74+
// Check for oauthAccount which indicates successful OAuth authentication
75+
if (data && typeof data === 'object' && (data.oauthAccount?.accountUuid || data.oauthAccount?.emailAddress)) {
76+
return true;
77+
}
78+
} catch (error) {
79+
// Log parse errors for debugging, but fall through to legacy checks
80+
console.warn(`[profile-utils] Failed to read or parse ${claudeJsonPath}:`, error);
81+
}
82+
}
83+
84+
// Legacy: Claude stores auth in .claude/credentials or similar files
6885
// Check for common auth indicators
6986
const possibleAuthFiles = [
7087
join(configDir, 'credentials'),

apps/frontend/src/main/ipc-handlers/mcp-handlers.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ const DANGEROUS_FLAGS = new Set([
2828
'--require', '-r'
2929
]);
3030

31+
/**
32+
* Defense-in-depth: Shell metacharacters that could enable command injection
33+
* when shell: true is used on Windows
34+
*/
35+
const SHELL_METACHARACTERS = ['&', '|', '>', '<', '^', '%', ';', '$', '`', '\n', '\r'];
36+
3137
/**
3238
* Validate that a command is in the safe allowlist
3339
*/
@@ -39,11 +45,22 @@ function isCommandSafe(command: string | undefined): boolean {
3945
}
4046

4147
/**
42-
* Validate that args don't contain dangerous interpreter flags
48+
* Validate that args don't contain dangerous interpreter flags or shell metacharacters
4349
*/
4450
function areArgsSafe(args: string[] | undefined): boolean {
4551
if (!args || args.length === 0) return true;
46-
return !args.some(arg => DANGEROUS_FLAGS.has(arg));
52+
53+
// Check for dangerous interpreter flags
54+
if (args.some(arg => DANGEROUS_FLAGS.has(arg))) return false;
55+
56+
// On Windows with shell: true, check for shell metacharacters that could enable injection
57+
if (process.platform === 'win32') {
58+
if (args.some(arg => SHELL_METACHARACTERS.some(char => arg.includes(char)))) {
59+
return false;
60+
}
61+
}
62+
63+
return true;
4764
}
4865

4966
/**
@@ -171,7 +188,7 @@ async function checkCommandHealth(server: CustomMcpServer, startTime: number): P
171188
return resolve({
172189
serverId: server.id,
173190
status: 'unhealthy',
174-
message: 'Args contain dangerous interpreter flags',
191+
message: 'Args contain dangerous flags or shell metacharacters',
175192
checkedAt: new Date().toISOString(),
176193
});
177194
}
@@ -394,14 +411,17 @@ async function testCommandConnection(server: CustomMcpServer, startTime: number)
394411
return resolve({
395412
serverId: server.id,
396413
success: false,
397-
message: 'Args contain dangerous interpreter flags',
414+
message: 'Args contain dangerous flags or shell metacharacters',
398415
});
399416
}
400417

401418
const args = server.args || [];
419+
420+
// On Windows, use shell: true to properly handle .cmd/.bat scripts like npx
402421
const proc = spawn(server.command!, args, {
403422
stdio: ['pipe', 'pipe', 'pipe'],
404423
timeout: 15000, // OS-level timeout for reliable process termination
424+
shell: process.platform === 'win32', // Required for Windows to run npx.cmd
405425
});
406426

407427
let stdout = '';

0 commit comments

Comments
 (0)